[树套树] Jzoj P5699 【gdoi2018 day1】涛涛接苹果

Description


 

Input

Output

 

Sample Input

10 5 6
1 2 3 4 5 6 7 8 9 10
9 7
7 10
6 5
7 5
5 8
5 1
2 1
3 2
2 4
2 3 4
2 9 5
1 7 3
4 8 2
5 6 6
2 3
2 5
1 4
3 5
5 1
6 1


 

Sample Output

0
43
4
27
11
13
 
 

Data Constraint

 

Hint

 

题解

  • 垃圾题目毁我青春!!!
  • 考场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 }

 

 

 

posted @ 2018-07-14 20:46  BEYang_Z  阅读(249)  评论(0编辑  收藏  举报