【BZOJ3589】动态树
Description
别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件
事件0:
这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子.
事件1:
小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次.
Input
第一行一个整数n(1<=n<=200,000), 即节点数.
接下来n-1行, 每行两个数字u, v. 表示果子u和果子v之间有一条直接的边. 节点从1开始编号.
在接下来一个整数nQ(1<=nQ<=200,000), 表示事件.
最后nQ行, 每行开头要么是0, 要么是1.
如果是0, 表示这个事件是事件0. 这行接下来的2个整数u, delta表示以u为根的子树中的每个节点长出了delta个果子.
如果是1, 表示这个事件是事件1. 这行接下来一个整数K(1<=K<=5), 表示这次询问涉及K个树枝. 接下来K对整数u_k, v_k, 每个树枝从节点u_k到节点v_k. 由于果子数可能非常多, 请输出这个数模2^31的结果.
Output
对于每个事件1, 输出询问的果子数.
Sample Input
5
1 2
2 3
2 4
1 5
3
0 1 1
0 2 3
1 2 3 1 1 4
1 2
2 3
2 4
1 5
3
0 1 1
0 2 3
1 2 3 1 1 4
Sample Output
13
HINT
1 <= n <= 200,000, 1 <= nQ <= 200,000, K = 5.
生成每个树枝的过程是这样的:先在树中随机找一个节点, 然后在这个节点到根的路径上随机选一个节点, 这两个节点就作为树枝的两端.
题解:话说这题做法好多啊,容斥、打标记、黑科技。。。是数据比较良心的缘故?
我的做法也类似于黑科技吧?因为我们在查询时,会访问到线段树上许多个可能会重叠的区间,那么我给线段树的每个节点都增加一个时间标记。当我们在线段树找到一个合法的整区间后,还要继续判断这个区间的在当前的时间是否打过标记,然后继续向下查找。这样做的时间复杂度我也不太清楚,大概O(nlog3n)差不多吧?
#include <cstdio> #include <cstring> #include <iostream> #define lson x<<1 #define rson x<<1|1 using namespace std; const int maxn=200010; int n,m,cnt,now,ans; int to[maxn<<1],next[maxn<<1],head[maxn],v[maxn],fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn]; int tt[maxn<<2],ts[maxn<<2],s[maxn<<2],tm[maxn<<2],tn[maxn<<2],p[maxn],q[maxn]; void add(int a,int b) { to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; } void dfs1(int x) { siz[x]=1; for(int i=head[x];i!=-1;i=next[i]) { if(to[i]!=fa[x]) { fa[to[i]]=x,dep[to[i]]=dep[x]+1,dfs1(to[i]),siz[x]+=siz[to[i]]; if(siz[to[i]]>siz[son[x]]) son[x]=to[i]; } } } void dfs2(int x,int tp) { top[x]=tp,p[x]=++p[0]; if(son[x]) dfs2(son[x],tp); for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[x]&&to[i]!=son[x]) dfs2(to[i],to[i]); q[x]=p[0]; } void pushdown(int l,int r,int x) { if(tt[x]) tt[lson]=tt[rson]=tm[lson]=tm[rson]=tn[lson]=tn[rson]=tt[x],tt[x]=0; if(ts[x]) { int mid=l+r>>1; ts[lson]+=ts[x],ts[rson]+=ts[x],s[lson]+=(mid-l+1)*ts[x],s[rson]+=(r-mid)*ts[x],ts[x]=0; } } void pushup(int x) { tm[x]=max(tm[lson],tm[rson]); tn[x]=min(tn[lson],tn[rson]); s[x]=s[lson]+s[rson]; } void updata(int l,int r,int x,int a,int b,int c) { if(a<=l&&r<=b) { s[x]+=(r-l+1)*c,ts[x]+=c; return ; } pushdown(l,r,x); int mid=l+r>>1; if(a<=mid) updata(l,mid,lson,a,b,c); if(b>mid) updata(mid+1,r,rson,a,b,c); pushup(x); } void q2(int l,int r,int x) { if(tm[x]<now) { ans+=s[x],tm[x]=tn[x]=tt[x]=now; return ; } pushdown(l,r,x); int mid=l+r>>1; if(tn[lson]<now) q2(l,mid,lson); if(tn[rson]<now) q2(mid+1,r,rson); pushup(x); } void q1(int l,int r,int x,int a,int b) { if(a<=l&&r<=b) { if(tn[x]<now) q2(l,r,x); return ; } pushdown(l,r,x); int mid=l+r>>1; if(a<=mid) q1(l,mid,lson,a,b); if(b>mid) q1(mid+1,r,rson,a,b); pushup(x); } void ask(int x,int y) { if(dep[x]<dep[y]) swap(x,y); while(top[x]!=top[y]) { q1(1,n,1,p[top[x]],p[x]); x=fa[top[x]]; } q1(1,n,1,p[y],p[x]); } int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } int main() { n=rd(); int i,j,a,b,c; memset(head,-1,sizeof(head)); for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a); dep[1]=1,dfs1(1),dfs2(1,1); m=rd(); for(i=1;i<=m;i++) { if(!rd()) a=rd(),updata(1,n,1,p[a],q[a],rd()); else { c=rd(),now++,ans=0; for(j=1;j<=c;j++) a=rd(),b=rd(),ask(a,b); printf("%d ",ans&2147483647); } } return 0; }