[HNOI2015]接水果——整體二分
阿新 • • 發佈:2018-12-11
題目大意:
給定一顆樹和m條帶有權值的路徑以及q個路徑詢問,每次求m條路徑中且為給出的路徑的子路徑的第k小。
思路:
首先考慮怎麼判斷一條路經是不是一條路徑的子路徑,假設這條路徑在樹上拐彎,那麼包含它的路徑的兩個端點要分別在兩個子樹裡面,如果這條路徑在樹上不拐彎,假設\(v\)是深度大的那個,\(u\)是深度小的那個,那麼包含它的路徑要有一個端點在\(v\)的子樹內,另外一個端點在\(u\)連線\(v\)的那個兒子的子樹外。
於是上面的條件都可以用dfs序來判定,把每一條路徑表示成一個二維平面上的點\((u,v)\),每一個子路徑代表的範圍可以變成一個或者兩個矩形,一條路徑包含另外一條路徑當且僅當這條路徑在子路徑所表示的矩形內。
於是樹上的問題變成了平面上的問題,考慮整體二分,每次check變成了計算包含一個點的矩形的數量,直接掃描線即可計算即可。
#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i) #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i) #define MREP(i,x) for(int i=beg[x],v;v=to[i],i;i=las[i]) #define debug(x) cout<<#x<<"="<<x<<endl #define fi first #define se second #define mk make_pair #define pb push_back #define y1 wtcl typedef long long ll; using namespace std; void File(){ freopen("luogu3242.in","r",stdin); freopen("luogu3242.out","w",stdout); } template<typename T>void read(T &_){ T __=0,mul=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')mul=-1; ch=getchar(); } while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar(); _=__*mul; } const int maxn=40000+10; int n,m,q,b[maxn],tot,cnt,ans[maxn],st[maxn][21],Log[maxn],dep[maxn]; int L[maxn],cnt_dfn,R[maxn],sz[maxn]; int beg[maxn],to[maxn<<1],las[maxn<<1],cnte=1; void add(int u,int v){ las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; } void dfs_init(int u,int f){ sz[u]=1; st[u][0]=f; dep[u]=dep[f]+1; L[u]=++cnt_dfn; MREP(i,u)if(v!=f){ dfs_init(v,u); sz[u]+=sz[v]; } R[u]=L[u]+sz[u]-1; } struct Query{ int x,y,y1,y2,val,id,ty; //ty=0 fruit //ty=1 add to the BIT //ty=-1 erase from the BIT bool operator < (const Query & tt) const { if(x!=tt.x)return x<tt.x; return abs(ty)>abs(tt.ty); } }qu[maxn<<3],t1[maxn<<3],t2[maxn<<3]; int find(int x,int y){ DREP(i,Log[dep[x]-dep[y]],0) if(dep[st[x][i]]>dep[y]) x=st[x][i]; return x; } void init(){ read(n),read(m),read(q); REP(i,2,n)Log[i]=Log[i/2]+1; int u,v,val; REP(i,1,n-1)read(u),read(v),add(u,v); dfs_init(1,0); REP(j,1,20)REP(i,1,n) if((1<<j)<=dep[i]-1) st[i][j]=st[st[i][j-1]][j-1]; REP(i,1,m){ read(u),read(v),read(val); b[++tot]=val; if(L[u]>L[v])swap(u,v);//L[u]<L[v] if(R[u]<L[v]){ qu[++cnt]=(Query){L[u],0,L[v],R[v],val,0,1}; qu[++cnt]=(Query){R[u]+1,0,L[v],R[v],val,0,-1}; } else{ u=find(v,u); qu[++cnt]=(Query){1,0,L[v],R[v],val,0,1}; qu[++cnt]=(Query){L[u],0,L[v],R[v],val,0,-1}; qu[++cnt]=(Query){L[v],0,R[u]+1,n,val,0,1}; qu[++cnt]=(Query){R[v]+1,0,R[u]+1,n,val,0,-1}; } } sort(b+1,b+tot+1); tot=unique(b+1,b+tot+1)-b-1; REP(i,1,cnt)qu[i].val=lower_bound(b+1,b+tot+1,qu[i].val)-b; REP(i,1,q){ read(u),read(v),read(val); if(L[u]>L[v])swap(u,v); //cout<<L[u]<<" "<<L[v]<<endl; qu[++cnt]=(Query){L[u],L[v],0,0,val,i,0}; } sort(qu+1,qu+cnt+1); //REP(i,1,cnt)printf("%d %d %d %d\n",qu[i].x,qu[i].y1,qu[i].y2,qu[i].ty); } struct BIT{ int sum[maxn]; int lowbit(int x){return x&(-x);} void add(int p,int x){for(;p<=n;p+=lowbit(p))sum[p]+=x;} int query(int p){int ret=0;for(;p>=1;p-=lowbit(p))ret+=sum[p];return ret;} }T; void solve(int ql,int qr,int l,int r){ if(ql>qr || l>r)return; if(l==r){REP(i,ql,qr)if(!qu[i].ty)ans[qu[i].id]=b[l];return;} int c1=0,c2=0,mid=(l+r)>>1; REP(i,ql,qr)if(qu[i].ty){ if(qu[i].val<=mid)t1[++c1]=qu[i]; else t2[++c2]=qu[i]; if(qu[i].val<=mid){ T.add(qu[i].y1,qu[i].ty); T.add(qu[i].y2+1,-qu[i].ty); } //printf("%d %d %d %d\n",qu[i].x,qu[i].y1,qu[i].y2,qu[i].ty); } else{ int sum=T.query(qu[i].y); //printf("%d %d %d\n",qu[i].x,qu[i].y,sum); if(qu[i].val<=sum)t1[++c1]=qu[i]; else t2[++c2]=qu[i],t2[c2].val-=sum; } REP(i,1,c1)if(t1[i].ty){ T.add(t1[i].y1,-t1[i].ty); T.add(t1[i].y2+1,t1[i].ty); } REP(i,1,c1)qu[ql+i-1]=t1[i]; REP(i,1,c2)qu[ql+i+c1-1]=t2[i]; solve(ql,ql+c1-1,l,mid); solve(ql+c1,qr,mid+1,r); } int main(){ File(); init(); solve(1,cnt,1,tot); REP(i,1,q)printf("%d\n",ans[i]); return 0; }