洛谷应该是疯了,又给我推荐黑题,又花了一上午
闲话少说,先给链接
大致题意描述(语文不好请见谅):
给一棵树,再给P条路径,每条路径有权值。
有Q次询问,每次给一条路径和k,让你输出能完全覆盖这条路径的 第k大路径(的权值)
(a --> b) & (b --> a) are the same
我知道您肯定没看懂,所以您还是去打开链接看吧
先考虑如何得到完全覆盖的路径:
设水果路径起点为x,终点为y,且dep[x]
设盘子路径起点为a,终点为b
设一点dfs序为dfn,子树dfn最大的点的dfn为low(即dfn~low为这一棵子树的所有节点)
若lca(x,y)==x:
设w为 x --> y 路径上的第一个点(不包括x)
则有a在y子树内,b不在w子树内
即:dfn[y]<=dfn[a]<=low[y],且(1<=dfn[b]
else:
a、b两点都分别在x、y子树内
即:dfn[x]<=dfn[a]<=low[x],且dfn[y]<=dfn[b]<=low[y]
可以看出,我们成功把盘子变成了1或2个矩形,水果变成了点
那么题目转换为:求覆盖一个点的权值第k大的矩形(的权值)
考虑整体二分(不会的左转百度,因为我也不会)
在二分过程中,先用扫描线算法把矩形优化为一维线
然后将区间加改为差分,用树状数组维护前缀和(即单点值)
就可以求出每个点被覆盖了多少次辣
代码:
#include
#define sz 40040
using namespace std;
int n,m,Q,i,x,y,z,q[sz],tmp[sz],now[sz],ans[sz];
struct E{
int x1,x2,l1,r1,l2,r2,z;
E(){}
E(int _x1,int _x2,int _l1,int _r1,int _l2,int _r2,int _z){x1=_x1,x2=_x2,l1=_l1,r1=_r1,l2=_l2,r2=_r2,z=_z;}
}e[sz];//盘子
inline bool cmp(const E&a,const E&b){return a.zsize[son[x]]) son[x]=o;
}
}
void dfs2(int x,int tp)
{
dfn[x]=++cnt;top[x]=tp;
if (!son[x]) return (void)(low[x]=cnt);
dfs2(son[x],tp);
go(x) if (!dfn[o]) dfs2(o,o);
low[x]=cnt;
}
int lca_son(int x,int y)
{
int t;
if (dep[x]'9'||ch<'0') ch=getchar();
while (ch<='9'&&ch>='0') ret=ret*10+ch-48,ch=getchar();
return ret;
}
void init()
{
n=read();m=read();Q=read();
int i,j,x,y,z;
for (i=1;iqr) return;
int i,j,L=ql,R=qr;
if (l==r) {for (i=ql;i<=qr;i++) ans[a[q[i]].p]=e[l].z,cout<<(a[q[i]].k>1?"jkhh":"");return;}
int mid=(l+r)>>1,cb=0,cc=0;
for (i=l;i<=mid;i++)
{
if (e[i].l1<=e[i].r1)
{
b[++cb]=B(e[i].x1,e[i].l1,e[i].r1,1);
b[++cb]=B(e[i].x2+1,e[i].l1,e[i].r1,-1);
}
if (e[i].l2<=e[i].r2)
{
b[++cb]=B(e[i].x1,e[i].l2,e[i].r2,1);
b[++cb]=B(e[i].x2+1,e[i].l2,e[i].r2,-1);
}
}
for (i=ql;i<=qr;i++)//一个拆成俩(别问我为什么,我也不知道)
{
c[++cc]=C(a[q[i]].x,a[q[i]].y,i);
c[++cc]=C(a[q[i]].y,a[q[i]].x,i);
now[i]=0;
}
T++,sort(b+1,b+cb+1,cmpb),sort(c+1,c+cc+1,cmpc);
for (i=1,j=1;i<=cc;i++)
{
while (j<=cb&&b[j].x<=c[i].x) add(b[j].l,b[j].t),add(b[j].r+1,-b[j].t),j++;//差分加扫描线
now[c[i].p]+=query(c[i].y);
}
for (i=ql;i<=qr;i++) if (now[i]>=a[q[i]].k) tmp[L++]=q[i];else {tmp[R--]=q[i];a[q[i]].k-=now[i];}
for (i=ql;i<=qr;i++) q[i]=tmp[i];
solve(l,mid,ql,R);solve(mid+1,r,R+1,qr);
}
int main()
{
init();
solve(1,m,1,Q);
for (int i=1;i<=Q;i++) printf("%d\n",ans[i]);
}