BZOJ4009 [HNOI2015]接水果
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=4009
打了一会儿的整体二分了...于是就准备好了做这道题。
具体题解不想讲了,看看别人的就好:http://blog.csdn.net/thy_asdf/article/details/50363672
然后注意二维平面上其实我们是舍弃了一部分点的,就是类似要求横坐标一定要小于纵坐标这种...这样就不会算重或者算漏了...
上面这个的代码 就是if(x>y) swap(x,y)?...好吧诸如此类..
敲了比较久,感觉比较顺,结果发现样例都不能过?!然后我检查很久觉得二分没错之后,调试啊调试,检查啊检查,结果发现原来是树状数组的区间加减打挂了[以前都是打线段树,不过今天觉得树状数组常数这么小,还是要复习一下的吧...结果一打就挂...],后来发现是单点修改,所以只要一个简单的差分就好了...改完之后就A了
不过复杂度貌似和同机房的同学不一样?...我的是二分答案,他们的说是二分选哪个篮子,其实相当于离散化?...
反正最后他们的快一些...不过感觉我这个模板感觉很靠谱,我就不改了...反正复杂度是能过的就行了。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int in(){ int x=0;char ch=getchar(); while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } const int maxn=40010; const int INF=0x3f3f3f3f; struct Node{ int data,next; }node[maxn<<1]; #define now node[point].data #define then node[point].next struct Query{ int tp,x,y,k,cur,rk; }q[maxn*6],q1[maxn*6],q2[maxn*6]; int n,m,P,Idex; int tot,cnt; int b[maxn]; int tmp[maxn*6],ans[maxn]; int head[maxn],dfn[maxn],low[maxn]; int f[maxn][16],d[maxn]; void add_edge(int u,int v){ node[cnt].data=v;node[cnt].next=head[u];head[u]=cnt++; node[cnt].data=u;node[cnt].next=head[v];head[v]=cnt++; } void dfs(int x){ dfn[x]=++Idex; for(int i=1;i<=15;i++) f[x][i]=f[f[x][i-1]][i-1]; for(int point=head[x];point!=-1;point=then) if(now!=f[x][0]) f[now][0]=x,d[now]=d[x]+1,dfs(now); low[x]=Idex; } int LCA(int x,int y){ int tmp=d[x]-d[y]; for(int i=15;i>=0;i--) if(tmp&(1<<i)) x=f[x][i]; if(x==y) return x; for(int i=15;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int get_fa(int x,int k){ for(int i=0;i<=15;i++) if((1<<i)&k) x=f[x][i]; return x; } void add2(int x,int d){ for(int i=x;i<=n;i+=i&-i) b[i]+=d; } void add(int l,int r,int d){ add2(l,d),add2(r+1,-d); } int ask(int x){ int sum=0; for(int i=x;i;i-=i&-i) sum+=b[i]; return sum; } void div(int H,int T,int l,int r){ if(H>T) return ; if(l==r){ for(int i=H;i<=T;i++) if(q[i].tp==3) ans[q[i].y]=l; return ; } int mid=(l+r)>>1; for(int i=H;i<=T;i++){ if(q[i].tp==1 && q[i].k<=mid) add(q[i].x,q[i].y,1); else if(q[i].tp==2 && q[i].k<=mid) add(q[i].x,q[i].y,-1); else if(q[i].tp==3) tmp[i]=ask(q[i].x); } for(int i=H;i<=T;i++){ if(q[i].tp==1 && q[i].k<=mid) add(q[i].x,q[i].y,-1); else if(q[i].tp==2 && q[i].k<=mid) add(q[i].x,q[i].y,1); } int l1=0,l2=0; for(int i=H;i<=T;i++){ if(q[i].tp==3){ if(q[i].cur+tmp[i]>=q[i].k) q1[++l1]=q[i]; else q[i].cur+=tmp[i],q2[++l2]=q[i]; } else{ if(q[i].k<=mid) q1[++l1]=q[i]; else q2[++l2]=q[i]; } } for(int i=1;i<=l1;i++) q[H+i-1]=q1[i]; for(int i=1;i<=l2;i++) q[H+l1+i-1]=q2[i]; div(H,H+l1-1,l,mid); div(H+l1,T,mid+1,r); } bool cmp(const Query &A,const Query &B){ if(A.rk!=B.rk) return A.rk<B.rk; return A.tp<B.tp; } int main(){ #ifndef ONLINE_JUDGE freopen("fruit.in","r",stdin); freopen("fruit.out","w",stdout); #endif int u,v,v1,w; n=in();P=in();m=in(); for(int i=1;i<=n;i++) head[i]=-1; for(int i=1;i<n;i++) u=in(),v=in(),add_edge(u,v); dfs(1); for(int i=1;i<=P;i++){ u=in(),v=in(),w=in(); if(d[u]>d[v]) swap(u,v); if(LCA(v,u)==u){ v1=get_fa(v,d[v]-d[u]-1); q[++tot].tp=1,q[tot].rk=1,q[tot].x=dfn[v],q[tot].y=low[v],q[tot].k=w; q[++tot].tp=2,q[tot].rk=dfn[v1],q[tot].x=dfn[v],q[tot].y=low[v],q[tot].k=w; if(low[v1]+1<=n){ q[++tot].tp=1,q[tot].rk=dfn[v],q[tot].x=low[v1]+1,q[tot].y=n,q[tot].k=w; q[++tot].tp=2,q[tot].rk=low[v]+1,q[tot].x=low[v1]+1,q[tot].y=n,q[tot].k=w; } } else{ if(dfn[u]<dfn[v]) swap(u,v); q[++tot].tp=1,q[tot].rk=dfn[v],q[tot].x=dfn[u],q[tot].y=low[u],q[tot].k=w; q[++tot].tp=2,q[tot].rk=low[v]+1,q[tot].x=dfn[u],q[tot].y=low[u],q[tot].k=w; } } for(int i=1;i<=m;i++){ u=in(),v=in(); if(dfn[u]<dfn[v]) swap(u,v); q[++tot].rk=dfn[v],q[tot].x=dfn[u]; q[tot].tp=3,q[tot].y=i,q[tot].k=in(); } sort(q+1,q+tot+1,cmp); div(1,tot,0,INF); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }