[树套树] Jzoj P5699 【gdoi2018 day1】涛涛接苹果
题解
- 垃圾题目毁我青春!!!
- 考场MLE,还我50分!!!
- 题目大意:给一颗根为1的树,树上每个结点有一个权值
- 每过1个时间单位,每个结点会走到其父亲,父亲的权值就是所有儿子的权值,结点1会消失
- 询问某个时间某颗子树的权值和
- 如果一个结点会被查询到,仅在它在出现在x的结点时,在被查询结点的子树里
- 设t[x]当前结点的权值出现在x点的时间,会被y结点在time时间查询
- 那么绝对满足:
- ①x在y的子树里
- ②dep[x]-dep[y]>=t[y]-t[x]且t[x]<=t[y]
- 将其移项:dep[x]+t[x]>=dep[y]+t[y]
- 那么左边只于x有关,右边只于y有关
- 考虑用dfs序就求出dfn[i]
- 然后就可以将题目中的第x个数字变成二维平面上的一个带权点
- 横坐标为dep[x]+t[x],纵坐标为dfn[x],权值为这个数字
- 那么询问就相当于询问一个矩阵的点权和
- 为了支持平面上单点修改和矩阵求和
- 要一个可以解决二维问题的数据结构
- 就是树套树
- 这里我打的是树状数组套线段树
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <cctype> 6 using namespace std; 7 const int N=1e5+5; 8 struct node { int mf,t,w,x; }a[N*3]; 9 struct edge { int from,to; }e[N*2]; 10 int tot,num,head[N],dep[N],dfn[N],size[N],id[N*3],cnt,en[N*2],nex[N*2],first[N*2]; 11 long long f[N],ans[N]; 12 inline int read() 13 { 14 int X=0,w=0; char ch=0; 15 while(!isdigit(ch)) w|=ch=='-',ch=getchar(); 16 while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); 17 return w?-X:X; 18 } 19 void insert(int x,int y) 20 { 21 e[++tot].to=y; e[tot].from=head[x]; head[x]=tot; 22 } 23 void dfs(int x,int y) 24 { 25 dfn[x]=++tot; 26 dep[x]=dep[y]+1; 27 size[x]=1; 28 for (int i=head[x];i;i=e[i].from) 29 if (e[i].to^y) 30 { 31 dfs(e[i].to,x); 32 size[x]+=size[e[i].to]; 33 } 34 } 35 bool cmp(node a,node b) 36 { 37 return a.t<b.t||a.t==b.t&&!a.mf&&b.mf; 38 } 39 bool cmp1(int x,int y) 40 { 41 return a[x].t>a[y].t; 42 } 43 long long find(int x) 44 { 45 long long sum=0; 46 while (x) sum+=f[x],x-=x&-x; 47 return sum; 48 } 49 void change(int x,int y) 50 { 51 while (x<N) f[x]=y?f[x]+y:0,x+=x&-x; 52 } 53 void solve(int l,int r) 54 { 55 if (l==r) return; 56 int mid=(l+r)>>1,k=l-1,k1=mid; 57 for (int i=l;i<=mid;i++) if (!a[i].mf) id[++k]=i; 58 for (int i=mid+1;i<=r;i++) if (a[i].mf) id[++k1]=i; 59 if (k>=l&&k1>mid) 60 { 61 sort(id+l,id+1+k,cmp1); 62 sort(id+mid+1,id+k1+1,cmp1); 63 int j=l; 64 for (int i=mid+1;i<=k1;i++) 65 { 66 while (j<=k&&a[id[j]].t>=a[id[i]].t) 67 { 68 change(dfn[a[id[j]].x],a[id[j]].w); 69 j++; 70 } 71 ans[a[id[i]].w]+=find(dfn[a[id[i]].x]+size[a[id[i]].x]-1)-find(dfn[a[id[i]].x]-1); 72 } 73 for (int i=l;i<=k;i++) change(dfn[a[id[i]].x],0); 74 } 75 if (k>=l&&k<mid) solve(l,mid); 76 if (k1>mid&&k1<r) solve(mid+1,r); 77 } 78 int main() 79 { 80 int n=read(),m=read(),q=read(); 81 for(int i=1;i<=n;i++) a[++num].x=i,a[num].t=1,a[num].w=read(); 82 for(int i=1;i<n;i++) 83 { 84 int x=read(),y=read(); 85 insert(x,y),insert(y,x); 86 } 87 dfs(1,tot=0); 88 for(int i=1;i<=m;i++) a[++num].t=read()+1,a[num].x=read(),a[num].w=read(); 89 for(int i=1;i<=q;i++) a[++num].mf=1,a[num].t=read(),a[num].x=read(),a[num].w=i; 90 sort(a+1,a+1+num,cmp); 91 for(int i=1;i<=num;i++) a[i].t+=dep[a[i].x]; 92 solve(1,num); 93 for (int i=1;i<=q;i++) printf("%lld\n",ans[i]); 94 }