HNOI2015 接水果
题意:
给你一棵个点的树和条路径,每条路径都有一个权值。
有k组询问,每次询问给你一条路径和一个值。
问你被这条路径包含的所有路径中的第K小的路径的值
题解:
我用的是树上莫队+平衡树(或分块)的方法
平衡树的话是,分块的话就是
稍微口胡一下树上莫队:
把一颗树的欧拉序搞出来,对于查询的两点(假设入栈早)。
如果是一条链,
否则,,同时莫队是要加入
平衡树有什么用?
我们看到题目中求第K大的值,就想到了用平衡树来维护值。
因为平衡树支持插入,删除和查找K大值,和莫队很配。
但其实分块更加优,分块能更好的和莫队配合。
因为分块的插入,查询,总的复杂度是(n,m同阶)
现在要处理的就是如何判断一条路径被包含,或者不被包含。
我们把每条路径看成两个点,如果这两个点都被包含,那么这条路径就是被包含的。
我们只要在莫队时记录一下每条路径两个端点被包含的个数即可。
由于同一个点可能是多条路径的端点,所以我们对每个点建一个vector,
我口胡一下分块的做法,因为更优(我一开始没想到)
先离散化,原来把值x插入平衡树(求第K大),现在就插入值域分块,
查询第K大,分块可以求出。
直接扫每一个块,扫到第一个 个数>=K的那个块停下来,再在块内暴力找。
代码:
(平衡树)
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #pragma GCC optimize("-fgcse") #pragma GCC optimize("-fgcse-lm") #pragma GCC optimize("-fipa-sra") #pragma GCC optimize("-ftree-pre") #pragma GCC optimize("-ftree-vrp") #pragma GCC optimize("-fpeephole2") #pragma GCC optimize("-ffast-math") #pragma GCC optimize("-fsched-spec") #pragma GCC optimize("unroll-loops") #pragma GCC optimize("-falign-jumps") #pragma GCC optimize("-falign-loops") #pragma GCC optimize("-falign-labels") #pragma GCC optimize("-fdevirtualize") #pragma GCC optimize("-fcaller-saves") #pragma GCC optimize("-fcrossjumping") #pragma GCC optimize("-fthread-jumps") #pragma GCC optimize("-funroll-loops") #pragma GCC optimize("-freorder-blocks") #pragma GCC optimize("-fschedule-insns") #pragma GCC optimize("inline-functions") #pragma GCC optimize("-ftree-tail-merge") #pragma GCC optimize("-fschedule-insns2") #pragma GCC optimize("-fstrict-aliasing") #pragma GCC optimize("-falign-functions") #pragma GCC optimize("-fcse-follow-jumps") #pragma GCC optimize("-fsched-interblock") #pragma GCC optimize("-fpartial-inlining") #pragma GCC optimize("no-stack-protector") #pragma GCC optimize("-freorder-functions") #pragma GCC optimize("-findirect-inlining") #pragma GCC optimize("-fhoist-adjacent-loads") #pragma GCC optimize("-frerun-cse-after-loop") #pragma GCC optimize("inline-small-functions") #pragma GCC optimize("-finline-small-functions") #pragma GCC optimize("-ftree-switch-conversion") #pragma GCC optimize("-foptimize-sibling-calls") #pragma GCC optimize("-fexpensive-optimizations") #pragma GCC optimize("inline-functions-called-once") #pragma GCC optimize("-fdelete-null-pointer-checks") #include<bits/stdc++.h> using namespace std; const int N=1e6+5; #define re register int n,m,k,l,r,top,t,len; int root,ncnt,fa[N*5],size[N*5],cnt[N*5],val[N*5],ch[N*5][2]; int a[N],ru[N],chu[N],rev[N],head[N],Ans[N],gs[N],used[N],f[N][20]; struct node{ int l,r,id,lca,k; }q[N]; struct node2{ int too,next; }edge[N]; vector<int>v[N]; char buf[1<<21],*p1=buf,*p2=buf; inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} inline int read() { int ret=0,f=0;char c=gc(); while(!isdigit(c)){if(c=='-')f=1;c=gc();} while(isdigit(c)){ret=ret*10+c-48;c=gc();} if(f)return -ret;return ret; } void write(int x){ if(x>=10) write(x/10); putchar(x%10+48); } inline void writeln(int x){ write(x); putchar('\n'); } inline bool chk(int x) { return ch[fa[x]][1]==x; } inline void pushup(int x) { size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x]; } inline void Zhuan(int x) { int y=fa[x],z=fa[y],k=chk(x),w=ch[x][k^1]; ch[y][k]=w; fa[w]=y; ch[z][chk(y)]=x; fa[x]=z; ch[x][k^1]=y; fa[y]=x; pushup(y);pushup(x); } inline void splay(int x,int gen=0) { while(fa[x]!=gen) { int y=fa[x],z=fa[y]; if(z!=gen) { if(chk(x)==chk(y))Zhuan(y); else Zhuan(x); } Zhuan(x); } if(!gen)root=x; } inline void insert(int x) { int u=root,p=0; while(u&&val[u]!=x) { p=u; u=ch[u][x>val[u]]; } if(u)cnt[u]++; else{ u=++ncnt; fa[u]=p; ch[p][x>val[p]]=u; ch[u][0]=ch[u][1]=0; size[u]=cnt[u]=1; val[u]=x; } splay(u); } inline int kth(int x) { int u=root; while(true) { if(ch[u][0]&&x<=size[ch[u][0]])u=ch[u][0]; else if(x>size[ch[u][0]]+cnt[u]) { x-=size[ch[u][0]]+cnt[u]; u=ch[u][1]; } else return u; } } inline void find(int x) { int u=root; while(x!=val[u]&&ch[u][x>val[u]])u=ch[u][x>val[u]]; splay(u); } inline int pre(int x) { find(x); if(val[root]<x)return root; int u=ch[root][0]; while(ch[u][1])u=ch[u][1]; return u; } inline int nxt(int x) { find(x); if(val[root]>x)return root; int u=ch[root][1]; while(ch[u][0])u=ch[u][0]; return u; } inline void Delete(int x) { int last=pre(x),next=nxt(x); splay(last); splay(next,last); int del=ch[next][0]; if(cnt[del]>1) { cnt[del]--; splay(del); } else ch[next][0]=0; } inline void add(int a,int b) { edge[++top].too=b;edge[top].next=head[a];head[a]=top; } void dfs(int u,int fa) { ru[u]=++t;rev[t]=u; f[u][0]=fa; for(re int i=head[u];i;i=edge[i].next) { int v=edge[i].too; if(v==fa)continue; dfs(v,u); } chu[u]=++t;rev[t]=u; } inline bool pd(int a,int b) { if((ru[b]<=ru[a])&&(chu[b]>=chu[a]))return true; return false; } inline int LCA(int x,int y) { if(pd(x,y))return y; if(pd(y,x))return x; int k=x; for(re int j=17;j>=0;j--) if((f[k][j]>0)&&(pd(y,f[k][j])==false))k=f[k][j]; return f[k][0]; } inline bool cmp(node a,node b) { return ((a.l/len)^(b.l/len))?(a.l<b.l):((a.l/len)&1)?(a.r<b.r):(a.r>b.r); } inline void add(int x) { for(re int i=0;i<v[x].size();i++) { gs[v[x][i]]++; if(gs[v[x][i]]==2)insert(a[v[x][i]]); } } inline void del(int x) { for(re int i=0;i<v[x].size();i++) { gs[v[x][i]]--; if(gs[v[x][i]]==1)Delete(a[v[x][i]]); } } inline void Add(int x) { if(used[x])del(x); else add(x); used[x]^=1; } int main() { n=read();m=read();k=read(); for(re int i=1;i<n;i++) { int x=read(),y=read(); add(x,y);add(y,x); } for(re int i=1;i<=m;i++) { int x=read(),y=read(); a[i]=read(); v[x].push_back(i); v[y].push_back(i); } dfs(1,0); for(re int i=1;i<=17;i++) for(re int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1]; len=sqrt(n); for(re int i=1;i<=k;i++) { q[i].id=i; int x=read(),y=read(); q[i].k=read(); if(ru[x]>ru[y])swap(x,y); int lca=LCA(x,y); if(lca==x)q[i].l=ru[x],q[i].r=ru[y],q[i].lca=0; else q[i].l=chu[x],q[i].r=ru[y],q[i].lca=lca; } sort(q+1,q+k+1,cmp); l=1;insert(1e9+1);insert(-1e9-1); for(re int i=1;i<=k;i++) { while(l>q[i].l){l--;Add(rev[l]);} while(r<q[i].r){r++;Add(rev[r]);} while(l<q[i].l){Add(rev[l]);l++;} while(r>q[i].r){Add(rev[r]);r--;} if(q[i].lca)Add(q[i].lca); Ans[q[i].id]=val[kth(q[i].k+1)]; if(q[i].lca)Add(q[i].lca); } for(int i=1;i<=k;i++)writeln(Ans[i]); return 0; }
(分块)
// luogu-judger-enable-o2 #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #pragma GCC optimize("-fgcse") #pragma GCC optimize("-fgcse-lm") #pragma GCC optimize("-fipa-sra") #pragma GCC optimize("-ftree-pre") #pragma GCC optimize("-ftree-vrp") #pragma GCC optimize("-fpeephole2") #pragma GCC optimize("-ffast-math") #pragma GCC optimize("-fsched-spec") #pragma GCC optimize("unroll-loops") #pragma GCC optimize("-falign-jumps") #pragma GCC optimize("-falign-loops") #pragma GCC optimize("-falign-labels") #pragma GCC optimize("-fdevirtualize") #pragma GCC optimize("-fcaller-saves") #pragma GCC optimize("-fcrossjumping") #pragma GCC optimize("-fthread-jumps") #pragma GCC optimize("-funroll-loops") #pragma GCC optimize("-freorder-blocks") #pragma GCC optimize("-fschedule-insns") #pragma GCC optimize("inline-functions") #pragma GCC optimize("-ftree-tail-merge") #pragma GCC optimize("-fschedule-insns2") #pragma GCC optimize("-fstrict-aliasing") #pragma GCC optimize("-falign-functions") #pragma GCC optimize("-fcse-follow-jumps") #pragma GCC optimize("-fsched-interblock") #pragma GCC optimize("-fpartial-inlining") #pragma GCC optimize("no-stack-protector") #pragma GCC optimize("-freorder-functions") #pragma GCC optimize("-findirect-inlining") #pragma GCC optimize("-fhoist-adjacent-loads") #pragma GCC optimize("-frerun-cse-after-loop") #pragma GCC optimize("inline-small-functions") #pragma GCC optimize("-finline-small-functions") #pragma GCC optimize("-ftree-switch-conversion") #pragma GCC optimize("-foptimize-sibling-calls") #pragma GCC optimize("-fexpensive-optimizations") #pragma GCC optimize("inline-functions-called-once") #pragma GCC optimize("-fdelete-null-pointer-checks") #include<bits/stdc++.h> using namespace std; const int N=1e6+5; #define re register int n,m,k,l,r,top,t,len; int root,ncnt,size,num,xu[N],sum[N],bel[N],L[N],R[N],b[N]; int a[N],ru[N],chu[N],rev[N],head[N],Ans[N],gs[N],used[N],f[N][20]; struct node{ int l,r,id,lca,k; }q[N]; struct node2{ int too,next; }edge[N]; vector<int>v[N]; //char buf[1<<21],*p1=buf,*p2=buf; //inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} #define gc getchar inline int read() { int ret=0,f=0;char c=gc(); while(!isdigit(c)){if(c=='-')f=1;c=gc();} while(isdigit(c)){ret=ret*10+c-48;c=gc();} if(f)return -ret;return ret; } void write(int x){ if(x>=10) write(x/10); putchar(x%10+48); } inline void writeln(int x){ write(x); putchar('\n'); } inline void insert(int x) { xu[x]++;sum[bel[x]]++; } inline void Delete(int x) { xu[x]--;sum[bel[x]]--; } inline void add(int a,int b) { edge[++top].too=b;edge[top].next=head[a];head[a]=top; } void dfs(int u,int fa) { ru[u]=++t;rev[t]=u; f[u][0]=fa; for(re int i=head[u];i;i=edge[i].next) { int v=edge[i].too; if(v==fa)continue; dfs(v,u); } chu[u]=++t;rev[t]=u; } inline bool pd(int a,int b) { if((ru[b]<=ru[a])&&(chu[b]>=chu[a]))return true; return false; } inline int LCA(int x,int y) { if(pd(x,y))return y; if(pd(y,x))return x; int k=x; for(re int j=17;j>=0;j--) if((f[k][j]>0)&&(pd(y,f[k][j])==false))k=f[k][j]; return f[k][0]; } inline bool cmp(node a,node b) { return ((a.l/len)^(b.l/len))?(a.l<b.l):((a.l/len)&1)?(a.r<b.r):(a.r>b.r); } inline void add(int x) { for(re int i=0;i<v[x].size();i++) { gs[v[x][i]]++; if(gs[v[x][i]]==2)insert(a[v[x][i]]); } } inline void del(int x) { for(re int i=0;i<v[x].size();i++) { gs[v[x][i]]--; if(gs[v[x][i]]==1)Delete(a[v[x][i]]); } } inline void Add(int x) { if(used[x])del(x); else add(x); used[x]^=1; } inline int query(int x) { int i,S=0; for(i=1;i<=num;i++) { S+=sum[i]; if(S>=x)break; } for(int j=R[i];j>=L[i];j--) { if(S>x-xu[j]&&S<=x)return b[j]; S-=xu[j]; } } int main() { n=read();m=read();k=read(); for(re int i=1;i<n;i++) { int x=read(),y=read(); add(x,y);add(y,x); } for(re int i=1;i<=m;i++) { int x=read(),y=read(); a[i]=b[i]=read(); v[x].push_back(i); v[y].push_back(i); } sort(b+1,b+m+1); size=unique(b+1,b+m+1)-b-1; for(int i=1;i<=m;i++)a[i]=lower_bound(b+1,b+size+1,a[i])-b; int sz=sqrt(m); num=m/sz; if(m%sz)num++; for(int i=1;i<=m;i++)L[i]=m+1; for(int i=1;i<=m;i++) { bel[i]=(i-1)/sz+1; L[bel[i]]=min(L[bel[i]],i); R[bel[i]]=max(R[bel[i]],i); } dfs(1,0); for(re int i=1;i<=17;i++) for(re int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1]; len=sqrt(n); for(re int i=1;i<=k;i++) { q[i].id=i; int x=read(),y=read(); q[i].k=read(); if(ru[x]>ru[y])swap(x,y); int lca=LCA(x,y); if(lca==x)q[i].l=ru[x],q[i].r=ru[y],q[i].lca=0; else q[i].l=chu[x],q[i].r=ru[y],q[i].lca=lca; } sort(q+1,q+k+1,cmp); l=1; for(re int i=1;i<=k;i++) { while(l>q[i].l){l--;Add(rev[l]);} while(r<q[i].r){r++;Add(rev[r]);} while(l<q[i].l){Add(rev[l]);l++;} while(r>q[i].r){Add(rev[r]);r--;} if(q[i].lca)Add(q[i].lca); Ans[q[i].id]=query(q[i].k); if(q[i].lca)Add(q[i].lca); } for(int i=1;i<=k;i++)writeln(Ans[i]); return 0; }
xuxuxuxuxu 文章被收录于专栏
信息学竞赛