luogu3242 接水果 (整体二分+树状数组)
Posted ressed
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu3242 接水果 (整体二分+树状数组)相关的知识,希望对你有一定的参考价值。
考虑整体二分,问题就变成了每个(水果)路径有多少个满足条件(权值)的(盘子)子路径
考虑一个盘子(a,b)表示两端点(不妨设dfn[a]<dfn[b]),那么他能接到的水果(u,v)一定满足(不妨设dfn[u]<dfn[v]):
1.如果a是b的祖先,则u在(a的在(b,a)链上的孩子)这个子树外,v在b子树内
2.否则,u在a的子树内,v在b的子树内
那么把一个水果(a,b)看成是一个二维点(dfn[a],dfn[b]),对于每个盘子,就是做一个二维区间+1
差分以后变成一个二维数点问题,可以先按x排序,y用树状数组来解决
复杂度$O(nlog^2n)$
然而我写的常数过大哪都卡不过去
1 #include<bits/stdc++.h> 2 #define CLR(a,x) memset(a,x,sizeof(a)) 3 #define MP make_pair 4 using namespace std; 5 typedef long long ll; 6 typedef unsigned long long ull; 7 typedef pair<int,int> pa; 8 const int maxn=4e4+10,maxp=1e7+10; 9 10 inline ll rd(){ 11 ll x=0;char c=getchar();int neg=1; 12 while(c<‘0‘||c>‘9‘){if(c==‘-‘) neg=-1;c=getchar();} 13 while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar(); 14 return x*neg; 15 } 16 17 int N,P,Q; 18 int eg[maxn*2][2],egh[maxn],ect; 19 int dfn[maxn][2],tot; 20 int rt[maxn],fa[maxn][20],dep[maxn]; 21 int tr[maxn]; 22 23 inline int lowbit(int x){return x&(-x);} 24 25 inline void add(int x,int d){ 26 for(;x&&x<=N;x+=lowbit(x)) tr[x]+=d; 27 } 28 inline int query(int x){ 29 int re=0; 30 for(;x;x-=lowbit(x)) re+=tr[x]; 31 return re; 32 } 33 34 inline void adeg(int a,int b){ 35 eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect; 36 } 37 38 inline void dfs(int x){ 39 for(int i=0;fa[x][i]&&fa[fa[x][i]][i];i++){ 40 fa[x][i+1]=fa[fa[x][i]][i]; 41 } 42 dfn[x][0]=++tot; 43 for(int i=egh[x];i;i=eg[i][1]){ 44 int b=eg[i][0];if(b==fa[x][0]) continue; 45 fa[b][0]=x,dep[b]=dep[x]+1; 46 dfs(b); 47 }dfn[x][1]=tot; 48 } 49 50 inline int jump(int x,int d){ 51 for(int i=0;d;i++,d>>=1){ 52 if(d&1) x=fa[x][i]; 53 }return x; 54 } 55 56 int ans[maxn],nct; 57 pa val[maxn]; 58 struct Node{ 59 int a,b,d,v,i; 60 }op[maxn*9],tmp[maxn*9]; 61 62 inline void addnode(int x1,int x2,int y1,int y2,int v,int i){ 63 op[++nct]=(Node){x1,y1,1,v,i}; 64 if(x2<N&&y2<N) op[++nct]=(Node){x2+1,y2+1,1,v,i}; 65 if(x2<N) op[++nct]=(Node){x2+1,y1,-1,v,i}; 66 if(y2<N) op[++nct]=(Node){x1,y2+1,-1,v,i}; 67 } 68 69 inline void cover(int a,int b,int v,int i){ 70 if(dfn[a][0]>dfn[b][0]) swap(a,b); 71 if(dfn[a][1]>=dfn[b][1]){ 72 int x=jump(b,dep[b]-dep[a]-1); 73 addnode(1,dfn[x][0]-1,dfn[b][0],dfn[b][1],v,i); 74 addnode(dfn[b][0],dfn[b][1],dfn[x][1]+1,N,v,i); 75 }else{ 76 addnode(dfn[a][0],dfn[a][1],dfn[b][0],dfn[b][1],v,i); 77 } 78 } 79 80 inline void solve(int l,int r,int ql,int qr){ 81 if(l>r||ql>qr) return; 82 int m=ql+qr>>1; 83 // printf("~%d %d %d %d %d ",l,r,ql,qr,val[m]); 84 int p=l-1,q=r+1; 85 for(int i=l;i<=r;i++){ 86 if(op[i].d){ 87 if(MP(op[i].v,op[i].i)<=val[m]){ 88 add(op[i].b,op[i].d); 89 tmp[++p]=op[i]; 90 }else tmp[--q]=op[i]; 91 }else{ 92 int n=query(op[i].b); 93 if(n>=op[i].v){ 94 ans[op[i].i]=val[m].first; 95 tmp[++p]=op[i]; 96 }else if(n<op[i].v){ 97 op[i].v-=n; 98 tmp[--q]=op[i]; 99 } 100 } 101 102 } 103 for(int i=l;i<=r;i++){ 104 if(op[i].d){ 105 if(MP(op[i].v,op[i].i)<=val[m]){ 106 add(op[i].b,-op[i].d); 107 } 108 } 109 } 110 for(int i=l;i<=p;i++) op[i]=tmp[i]; 111 for(int i=q;i<=r;i++) op[r-i+q]=tmp[i]; 112 solve(l,p,ql,m-1),solve(q,r,m+1,qr); 113 } 114 115 inline bool cmp(Node a,Node b){return a.a==b.a?a.d!=0:a.a<b.a;} 116 117 int main(){ 118 // freopen("fruit1.in","r",stdin); 119 // freopen("aa.out","w",stdout); 120 int i,j,k; 121 N=rd(),P=rd(),Q=rd(); 122 for(i=1;i<N;i++){ 123 int a=rd(),b=rd(); 124 adeg(a,b);adeg(b,a); 125 } 126 dep[1]=1;dfs(1); 127 for(i=1;i<=P;i++){ 128 int a=rd(),b=rd(),c=rd(); 129 val[i]=MP(c,i); 130 cover(a,b,c,i); 131 }sort(val+1,val+P+1); 132 for(i=1;i<=Q;i++){ 133 int a=rd(),b=rd(),c=rd(); 134 if(dfn[a][0]>dfn[b][0]) swap(a,b); 135 op[++nct]=(Node){dfn[a][0],dfn[b][0],0,c,i}; 136 } 137 sort(op+1,op+nct+1,cmp); 138 solve(1,nct,1,P); 139 for(i=1;i<=Q;i++) printf("%d ",ans[i]); 140 return 0; 141 }
以上是关于luogu3242 接水果 (整体二分+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4009[HNOI2015]接水果 DFS序+整体二分+扫描线+树状数组