其实我真的不想写这道题,然而迫于有一个技巧,不得不写一写(主要是为了把技巧放进博客)
保证一个月内不写代码超过100行的。
Description
风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。
由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更
加难的版本。首先有一个地图,是一棵由 个顶点、 条边组成的树(例如图 1
给出的树包含 8 个顶点、7 条边)。这颗树上有 个盘子,每个盘子实际上是一条
路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 个
盘子就是顶点到顶点的路径(由于是树,所以从到的路径是唯一的),权值为。接下来依次会有个水果掉下来,每个水果本质上也是一条路径,第 个水果是从顶点 到顶点的路径。幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如图1中从 3到7 的路径是从1到8的路径的子路径)。这里规定:从 到b的路径与从到 的路径是同一条路径。当然为了提高难度,对于第 个水果,你需要选择能接住它的所有盘子中,权值第 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
Input
第一行三个数 和 和,表示树的大小和盘子的个数和水果的个数。
接下来 行,每行两个数 、,表示树上的和 之间有一条边。树中顶点按1到 标号。 接下来 行,每行三个数 、、,表示路径为 到 、权值为 的盘子,其中,不等于。
接下来行,每行三个数 、、,表示路径为 到的水果,其中 不等于,你需要选择第 小的盘子,
第 小一定存在。
Output
对于每个果子,输出一行表示选择的盘子的权值。
Sample Input
10 10 10 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 3 2 217394434 10 7 13022269 6 7 283254485 6 8 333042360 4 6 442139372 8 3 225045590 10 4 922205209 10 8 808296330 9 2 486331361 4 9 551176338 1 8 5 3 8 3 3 8 4 1 8 3 4 8 1 2 3 1 2 3 1 2 3 1 2 4 1 1 4 1
Sample Output
442139372 333042360 442139372 283254485 283254485 217394434 217394434 217394434 217394434 217394434
HINT
。
这道题首先需要解决的问题是如何判断水果是否出现在盘子上。而且,我们对于一个盘子,要很快地求出有多少个水果经过它。
搬运
首先得到每个节点的序和以这个节点为根的子树中序最大值,分别记作和
显然,A路径覆盖B路径当且仅当B路径的两个端点都在A路径上
对于每一个盘子(假设),有以下两种情况
1.时,如图
(虚线表示有一条路径,实线表示一条边,下同)
显然这个盘子能接到的水果(假设,下同)满足 &&
2.当时,如图
设Ϊ在这条路径上的儿子节点
则这个盘子能接到的水果满足&&
我们可以将水果看成平面上的一个点,将盘子看成一个或两个矩形
那么问题就转化为对于平面上的一个点,求覆盖它的第小的矩形
这是一个整体二分的经典题,用扫描线+树状数组搞定
我们先将矩形按权值从小到大排序
然后对于一个点,如果[l,mid]中能覆盖这个点的矩形数不小于,则说明答案在[l,mid]中
否则在[mid+1,r],同时减去覆盖的矩形数
大佬说的很清楚啦~
发现整体二分似乎并不能先把矩阵拆成扫描线,要在二分中间拆成扫描线。不知道是不是姿势不对?似乎两个边界会被分到两边,对答案有问题?
我就只好把矩形二分,然后要算的时候就直接拆成扫描线。
唉,怕不是写假了,别人都只写了100行多一点。不知道是树剖长了还是整体二分长了。怕不是都长了。
反正都180行了,根本不想卡常,sort算了。-_-
code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define lowbit(x) ((x)&(-x)) using namespace std; int key; struct lxy{ int next,to; }eg[80005]; struct lxy2{ int xl,xr,yl,yr,k; bool operator < (const lxy2 &QAQ)const{ if(key==0) return k<QAQ.k; } }d[200005]; struct lxy3{ int l,r,k,tim,ans; bool operator < (const lxy3 &QAQ)const{ if(key==0) return tim<QAQ.tim; if(key==1) return l<QAQ.l; } }f[40005],tax[40005]; struct lxy4{ int x,yl,yr,type; bool operator < (const lxy4 &QAQ)const{ if(key==1) return x<QAQ.x; } }s[200005]; int n,p,q,x,y,k,cnt,tim,kl; int head[40005],tp[40005],fa[40005],dep[40005],size[40005],wson[40005],dfn[40005],last[40005]; bool vis[40005]; int b[40005]; void add(int op,int ed) { eg[++cnt].next=head[op]; eg[cnt].to=ed; head[op]=cnt; } void dfs1(int u,int dp) { vis[u]=1;dep[u]=dp;size[u]=1;dfn[u]=++tim; int t=0; for(int i=head[u];i!=-1;i=eg[i].next) if(vis[eg[i].to]==0) { fa[eg[i].to]=u; dfs1(eg[i].to,dp+1); size[u]+=size[eg[i].to]; if(size[eg[i].to]>t){ t=size[eg[i].to]; wson[u]=eg[i].to; } } vis[u]=0; } int dfs2(int u,int las) { tp[u]=las;vis[u]=1;last[u]=dfn[u]; if(wson[u]!=0) last[u]=max(last[u],dfs2(wson[u],las)); for(int i=head[u];i!=-1;i=eg[i].next) if(vis[eg[i].to]==0&&eg[i].to!=wson[u]) last[u]=max(last[u],dfs2(eg[i].to,eg[i].to)); vis[u]=0; return last[u]; } bool lca(int w,int v) { int fro=v; while(tp[w]!=tp[v]&&v!=0){ fro=tp[v],v=fa[tp[v]]; } if(v==0||dep[v]<dep[w]) return true; if(v==w) kl=fro; else kl=wson[w]; return false; } void modify(int u,int r){ while(u<=n){ b[u]+=r; u+=lowbit(u); } } int query(int u){ int ret=0; while(u>0){ ret+=b[u]; u-=lowbit(u); } return ret; } void CDQ(int ml,int mr,int ql,int qr) { if(ml==mr){ for(int i=ql;i<=qr;i++) f[i].ans=d[ml].k; return; } int mid=(ml+mr)>>1,cnt_=0; for(int i=ml;i<=mid;i++){ s[++cnt_].x=d[i].xl;s[cnt_].yl=d[i].yl;s[cnt_].yr=d[i].yr;s[cnt_].type=1; s[++cnt_].x=d[i].xr;s[cnt_].yl=d[i].yl;s[cnt_].yr=d[i].yr;s[cnt_].type=-1; } int t1=1,t2=ql,l=ql-1,r=qr+1; key=1,sort(s+1,s+cnt_+1),sort(f+ql,f+qr+1); while(t2<=qr){ if(t1<=cnt_&&s[t1].x<=f[t2].l){ modify(s[t1].yl,s[t1].type); modify(s[t1].yr+1,-s[t1].type); t1++; } else{ int z=query(f[t2].r); if(z<f[t2].k) f[t2].k-=z,tax[--r]=f[t2]; else tax[++l]=f[t2]; t2++; } } for(int i=1;i<t1;i++){ modify(s[i].yl,-s[i].type); modify(s[i].yr+1,s[i].type); } for(int i=ql;i<=qr;i++) f[i]=tax[i]; CDQ(ml,mid,ql,l); CDQ(mid+1,mr,r,qr); } int main() { memset(head,-1,sizeof(head)); scanf("%d%d%d",&n,&p,&q); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y);add(y,x); } dfs1(1,1);dfs2(1,1); cnt=0; for(int i=1;i<=p;i++){ scanf("%d%d%d",&x,&y,&k); if(dfn[x]>dfn[y]) swap(x,y); if(lca(x,y)){ d[++cnt].xl=dfn[x];d[cnt].xr=last[x]+1;d[cnt].yl=dfn[y];d[cnt].yr=last[y];d[cnt].k=k; } else{ d[++cnt].xl=1;d[cnt].xr=dfn[kl];d[cnt].yl=dfn[y];d[cnt].yr=last[y];d[cnt].k=k; d[++cnt].xl=dfn[y];d[cnt].xr=last[y]+1;d[cnt].yl=last[kl]+1;d[cnt].yr=n;d[cnt].k=k; } } for(int i=1;i<=q;i++){ scanf("%d%d%d",&x,&y,&f[i].k); f[i].tim=i; f[i].l=min(dfn[x],dfn[y]); f[i].r=max(dfn[x],dfn[y]); } key=0,sort(d+1,d+1+cnt); CDQ(1,cnt,1,q); key=0,sort(f+1,f+q+1); for(int i=1;i<=q;i++) printf("%d\n",f[i].ans); }