您的位置:首页 > 其它

bzoj2588 Count on a tree

2016-10-28 16:58 204 查看
题意:给定一棵树,有点权,不带修改,询问路径点权第K大,强制在线。

这道题建主席树的方法好机智。按照BFS/DFS序建树,对于每个点,建出“这个点到根节点的路径上的点”组成的权值线段树,某个节点的树由父节点的树更改一条链得来。查询时用路径两个端点到根的线段树减去lca到根节点的线段树的2倍就得到了这条路径。注意lca的点权要特殊处理一下,不要把lca多减一次。据说只要分别减去lca和lca的父亲即可,查询的时候传4棵线段树的节点。

于是抖机灵强行传3个节点,单独处理lca,结果RE了一坨…..因为lca的权值小于区间中点的权值并不一定是lca处在[l,r]区间的左半部分,还有可能是lca在[l,r]区间的左边,加句rk[lca]>=l就过了.调了一小时,虚死….

#include<cstdio>

#include<algorithm>

using namespace std;

const int maxn=100005;

int n,m;

struct edge{

int to,next;

}lst[maxn<<1];int len=1;

int first[maxn];

void addedge(int a,int b){

lst[len].to=b;

lst[len].next=first[a];

first[a]=len++;

}

int c[maxn];

int q[maxn];

int depth[maxn],p[maxn][18];

void bfs(){

int head=0,tail=0;

depth[1]=1;

q[tail++]=1;

int x;

while(head!=tail){

x=q[head++];

for(int pt=first[x];pt;pt=lst[pt].next){

if(lst[pt].to==p[x][0])continue;

p[lst[pt].to][0]=x;

depth[lst[pt].to]=depth[x]+1;

q[tail++]=lst[pt].to;

}

for(int j=0;p[x][j];++j)p[x][j+1]=p[p[x][j]][j];

}

}

int LCA(int u,int v){

if(depth[u]<depth[v])swap(u,v);

for(int j=17;j>=0;--j){

if(depth[p[u][j]]>=depth[v])u=p[u][j];

}

if(u==v)return u;

for(int j=17;j>=0;--j){

if(p[u][j]!=p[v][j]){

u=p[u][j];v=p[v][j];

}

}

return p[u][0];

}

struct node{

int sum;

node *lch,*rch;

node(){

lch=rch=0;

sum=0;

}

}t[maxn*50];int cnt=0;

int tot=0;

node *root[maxn];

int qx;

int seq[maxn],dict[maxn],rk[maxn];

void Insert(node *rt1,node* &rt2,int l,int r){

++cnt;rt2=t+cnt;

if(l==r){

rt2->sum=rt1->sum+1;

rt2->lch=rt2->rch=t+0;

return;

}

int mid=(l+r)>>1;

if(qx<=mid){

rt2->rch=rt1->rch;

Insert(rt1->lch,rt2->lch,l,mid);

}else{

rt2->lch=rt1->lch;

Insert(rt1->rch,rt2->rch,mid+1,r);

}

rt2->sum=rt2->lch->sum+rt2->rch->sum;

}

void build_all(){

root[0]=t+0;

root[0]->rch=root[0]->lch=t+0;

root[0]->sum=0;

for(int i=0;i<n;++i){

qx=rk[q[i]];

Insert(root[p[q[i]][0]],root[q[i]],1,tot);

}

}

bool cmp(const int &x,const int &y){

return c[x]<c[y];

}

int lca;

int query(node *rt1,node *rt2,node *rt3,int l,int r){

if(l==r)return l;

int mid=(l+r)>>1;

int lsum=rt1->lch->sum+rt2->lch->sum-2*(rt3->lch->sum);

if(l<=rk[lca]&&rk[lca]<=mid)lsum++;

//if(rk[lca]<=mid) 错误的写法.这时rk[lca]可以小于l

if(qx<=lsum)return query(rt1->lch,rt2->lch,rt3->lch,l,mid);

else{

qx-=lsum;

return query(rt1->rch,rt2->rch,rt3->rch,mid+1,r);

}

}

int main(){

scanf("%d%d",&n,&m);

for(int i=1;i<=n;++i){

scanf("%d",c+i);

seq[i]=i;

}

sort(seq+1,seq+n+1,cmp);

int old=c[seq[1]]-1;

for(int i=1;i<=n;++i){

if(old!=c[seq[i]]){

old=c[seq[i]];++tot;

dict[tot]=c[seq[i]];

}

rk[seq[i]]=tot;

}

int a,b,k;

for(int i=1;i<n;++i){

scanf("%d%d",&a,&b);

addedge(a,b);addedge(b,a);

}

bfs();

build_all();

int lastans=0;

while(m--){

scanf("%d%d%d",&a,&b,&k);

a^=lastans;

qx=k;lca=LCA(a,b);

lastans=dict[query(root[a],root[b],root[lca],1,tot)];

if(m)printf("%d\n",lastans);

else printf("%d",lastans);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: