【SYZOI Round1】滑稽的树
Description
zzsyz实验楼里面种了一棵滑稽树,只有滑稽之力达到大乘期的oier才能看到。虽然我们看不到,但是还是知道一些信息:
这真的是一棵树,由n个节点,n-1条边联通。一号滑稽果同时也是整棵滑稽树的树根。滑稽树上每个节点有一个滑稽果,每个滑稽果有它的重量。
雪甜甜公主是神犇当然看得到那棵滑稽树啦,现在她感兴趣的是这样三件事
1:滑稽树太大啦,雪甜甜公主有的时候只想知道,在以某一个滑稽果为根的子滑稽树里面,重量第k小的果子的重量是多少?
2:除了重量第k小的果子,雪甜甜还想知道以某个滑稽果为根的子滑稽树里面,重量在[a, b]这个范围内的滑稽果有多少个。
3:雪甜甜还喜欢吃滑稽果,但是吃完,原来滑稽果的位置上还会长出一个新的滑稽果,只是重量可能不一样。
Input
第一行一个正整数n,表示滑稽树有n个节点。
第二行n个正整数,分别描述1号,2号,,,,n号节点滑稽果的重量。
接下来n-1行,每行2个正整数u, v ∈ [1, n],表示滑稽果u与滑稽果v之间有树枝连接。
接下来一个正整数q,表示雪甜甜有q次行动
之后q行,有这样3种形式
1 u k 雪甜甜公主询问以u为根的子滑稽树中,重量第k小的滑稽果的重量。
2 u a b 雪甜甜公主想知道,以u为根的子滑稽树中,重量在[a, b]范围内的滑稽果有多少个。
3 u x 雪甜甜公主吃掉了编号为u的滑稽果,但是在原位置上立刻长出来了一个重量为x的滑稽果。因为位置没有变,所以编号还是u。
Output
对于每次询问,输出结果。
Sample Input
5
3 4 6 1 2
1 2
1 3
3 4
3 5
7
1 1 4
2 1 1 5
3 4 5
1 1 4
2 3 3 6
3 5 7
1 3 3
Sample Output
4
4
5
2
7
Hint
样例提示:
数据的范围及提示:
N:
对于前35%的数据满足,N <= 5000
对于前50%的数据满足,N <= 10000
对于前100%的数据满足,N <= 30000
滑稽果的重量:对于100%d的数据满足 滑稽果的重量 <= 10000
询问:询问的个数Q:
对于前50%的数据满足 Q <= 10000
对于前100%的数据满足 Q <= 50000
对于前25%的数据,只有第一种询问。
对于前65%的数据,有第1,2种询问。
对于100%的数据第1,2,3种询问都存在。
对于前35%的数据,满足一个特殊的限制条件:每次询问的滑稽果u = 1保证询问k小重量的滑稽果的时候,k值∈ [1, 子树的节点数]
题解:
变样的整体二分,直接记录进出子树的时间戳就可以转化为区间问题,
值得注意的是查找[L,R]的个数 的地方很细节.
只有t[i].k>mid 时才可以统计,不能取等,不然就会被加入到q1 然后被重复统计
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 using namespace std; 8 const int N=30005,M=50005,Q=M*2+N; 9 const int INF=-2e8; 10 int head[N],num=0; 11 struct Lin{ 12 int next,to; 13 }b[N<<1]; 14 void init(int x,int y){ 15 b[++num].next=head[x]; 16 b[num].to=y; 17 head[x]=num; 18 } 19 int gi(){ 20 int str=0;char ch=getchar(); 21 while(ch>'9' || ch<'0')ch=getchar(); 22 while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar(); 23 return str; 24 } 25 int n,m,val[N]; 26 struct node{ 27 int ki,x,y,k,cnt,id; 28 }t[Q<<1],q1[Q<<1],q2[Q<<1]; 29 int dfn[N],last[N],dfns=0,tot=0; 30 void dfs(int x){ 31 dfn[x]=++dfns; 32 for(int i=head[x];i;i=b[i].next){ 33 if(!dfn[b[i].to])dfs(b[i].to); 34 } 35 last[x]=dfns; 36 } 37 int a[N],ans[M],Tree[N*4]; 38 void add(int sta,int ad){ 39 for(int i=sta;i<=n;i+=(i&(-i)))Tree[i]+=ad; 40 } 41 int getsum(int sta){ 42 int sum=0; 43 for(int i=sta;i>=1;i-=(i&(-i)))sum+=Tree[i]; 44 return sum; 45 } 46 int l1,l2; 47 void count(int ll,int rr,int dl,int dr) 48 { 49 l1=l2=0; 50 for(int i=ll;i<=rr;i++) 51 { 52 if(t[i].ki==1) 53 { 54 t[i].cnt=getsum(t[i].y)-getsum(t[i].x-1); 55 if(t[i].cnt>=t[i].k)q1[++l1]=t[i]; 56 else t[i].k-=t[i].cnt,q2[++l2]=t[i]; 57 } 58 else if(t[i].ki==2) 59 { 60 if(t[i].k>dr) 61 ans[t[i].id]+=(getsum(t[i].y)-getsum(t[i].x-1))*t[i].cnt,q2[++l2]=t[i]; 62 else 63 q1[++l1]=t[i]; 64 } 65 else 66 { 67 if(t[i].y<=dr)add(t[i].x,t[i].cnt),q1[++l1]=t[i]; 68 else q2[++l2]=t[i]; 69 } 70 } 71 for(int i=1;i<=l1;i++) 72 if(q1[i].ki==3) 73 add(q1[i].x,-q1[i].cnt); 74 int now=ll-1; 75 for(int i=1;i<=l1;i++) 76 t[++now]=q1[i]; 77 for(int i=1;i<=l2;i++) 78 t[++now]=q2[i]; 79 } 80 void div(int ll,int rr,int dl,int dr) 81 { 82 if(dl==dr){ 83 for(int i=ll;i<=rr;i++) 84 if(t[i].ki==1)ans[t[i].id]=dl; 85 return ; 86 } 87 int mid=(dl+dr)>>1; 88 count(ll,rr,dl,mid); 89 int p=l1; 90 if(p) 91 div(ll,ll+p-1,dl,mid); 92 if(p<=rr-ll) 93 div(ll+p,rr,mid+1,dr); 94 } 95 int main() 96 { 97 n=gi(); 98 for(int i=1;i<=n;i++) 99 val[i]=gi(); 100 int x,y; 101 for(int i=1;i<n;i++){ 102 x=gi();y=gi(); 103 init(x,y);init(y,x); 104 } 105 dfs(1); 106 for(int i=1;i<=n;i++){ 107 a[dfn[i]]=val[i]; 108 t[++tot]=(node){3,dfn[i],val[i],0,1,0}; 109 } 110 m=gi(); 111 int flag,z,qnum=0; 112 for(int i=1;i<=m;i++) 113 { 114 flag=gi(); 115 if(flag==1){ 116 x=gi();y=gi(); 117 t[++tot]=(node){1,dfn[x],last[x],y,0,++qnum}; 118 } 119 else 120 if(flag==2){ 121 x=gi();y=gi();z=gi(); 122 t[++tot]=(node){2,dfn[x],last[x],y,-1,++qnum}; 123 t[++tot]=(node){2,dfn[x],last[x],z+1,1,qnum}; 124 } 125 else{ 126 x=gi();y=gi(); 127 t[++tot]=(node){3,dfn[x],a[dfn[x]],0,-1,0}; 128 t[++tot]=(node){3,dfn[x],y,0,1,0}; 129 a[dfn[x]]=y; 130 } 131 } 132 div(1,tot,0,10000); 133 for(int i=1;i<=qnum;i++)printf("%d\n",ans[i]); 134 return 0; 135 }