題解 三隻企鵝
題目描述
數據範圍:
具體做法與心路歷程
考場上的錯誤方法不多說。
具體做法
我們把查詢操作寫出來:
我們發現前面兩個比較好求。重點是怎麼求。
因爲直接修改其他所有點的距離沒有優秀的方法,所以我們試着把修改改成差分。
對於,如果他們在的不同子樹中,那麼他們的,不用考慮。
也就是說,對於一個修改操作,他能影響到的點只在他所在的到根的子樹中。
我們把到根的路徑上的每個點都打一個標記,記的標記個數爲,考慮查詢時求出的每個祖先作爲的個數再來計算。
那麼有如下計算方式:
- 。
- 重複1,2,直到爲根
將以上拆開後把放在一起有:。那麼這個查詢就變成查詢到根上這些所有的和了。
我們可以輕易維護好(樹鏈剖分),那麼我們用線段樹維護每個點的的倍數,最後區間求和即可。(意思就是區間加時對於每個點加的值不一樣)
如果不清楚可以看代碼。
/*******************************
Author:galaxy yr
LANG:C++
Created Time:2019年10月28日 星期一 20時55分56秒
*******************************/
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
struct IO{
template<typename T>
IO & operator>>(T&res)
{
T q=1;char ch;
while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q;
res=(ch^48);
while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48);
res*=q;
return *this;
}
}cin;
struct edge{
int to,next,w;
edge(int a=0,int b=0,int c=0):to(a),next(b),w(c){}
};
const int maxn=2e5+10;
int n,m,head[maxn],cnt,f[maxn],top[maxn],size[maxn],seg[maxn],son[maxn],dis[maxn],tot,rev[maxn];
long long res;
edge e[maxn<<1];
void add(int u,int v,int w)
{
e[++cnt]=edge(v,head[u],w);
head[u]=cnt;
}
void dfs1(int now,int fa)
{
f[now]=fa; size[now]=1;
for(int i=head[now];i;i=e[i].next)
if(e[i].to!=fa)
{
dis[e[i].to]=dis[now]+e[i].w;
dfs1(e[i].to,now);
size[now]+=size[e[i].to];
if(size[son[now]]<size[e[i].to])
son[now]=e[i].to;
}
}
void dfs2(int now,int tp)
{
seg[now]=++seg[0];
rev[seg[0]]=now;
top[now]=tp;
if(son[now])
dfs2(son[now],tp);
for(int i=head[now];i;i=e[i].next)
if(e[i].to!=f[now] && e[i].to!=son[now])
dfs2(e[i].to,e[i].to);
}
/*{{{線段樹*/
namespace SegmentTree{
long long sum[maxn*4],lazy[maxn*4],delta[maxn*4];
void update(int k)
{
sum[k]=sum[k<<1]+sum[k<<1|1];
}
void work(int k,long long val)
{
sum[k]+=delta[k]*val;
lazy[k]+=val;
}
void pushdown(int k)
{
if(!lazy[k]) return;
work(k<<1,lazy[k]);
work(k<<1|1,lazy[k]);
lazy[k]=0;
}
void build(int k,int l,int r)
{
if(l==r)
{
delta[k]=dis[rev[l]]-dis[f[rev[l]]];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
delta[k]=delta[k<<1]+delta[k<<1|1];
}
void modify(int k,int l,int r,int x,int y,int val)
{
if(l>=x && r<=y) return work(k,val);
if(l>y || r<x) return;
int mid=(l+r)>>1;
pushdown(k);
modify(k<<1,l,mid,x,y,val); modify(k<<1|1,mid+1,r,x,y,val);
return update(k);
}
long long query(int k,int l,int r,int x,int y)
{
if(l>=x && r<=y) return sum[k];
if(l>y || r<x) return 0;
int mid=(l+r)>>1;
pushdown(k);
return query(k<<1,l,mid,x,y)+query(k<<1|1,mid+1,r,x,y);
}
};
/*}}}*/
void modify(int now)
{
++tot; res+=dis[now];
while(top[now])
{
SegmentTree::modify(1,1,seg[0],seg[top[now]],seg[now],1);
now=f[top[now]];
}
}
long long solve(int now)
{
long long res=::res+tot*dis[now];
while(top[now])
{
res-=2LL * SegmentTree::query(1,1,seg[0],seg[top[now]],seg[now]);
now=f[top[now]];
}
return res;
}
signed main()
{
/*freopen("express.in","r",stdin);*/
/*freopen("express.out","w",stdout);*/
cin>>n>>m;
int u,v,w;
for(int i=1;i<n;i++)
{
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
dfs1(1,0); dfs2(1,1);
SegmentTree::build(1,1,seg[0]);
while(m--)
{
int opt,u;
cin>>opt>>u;
if(opt==1)
modify(u);
else
printf("%lld\n",solve(u));
}
return 0;
}