首页 > 其他分享 >P4216[SCOI2015情报传递 树上主席树

P4216[SCOI2015情报传递 树上主席树

时间:2024-08-22 20:15:49浏览次数:8  
标签:return int st P4216 que SCOI2015 树上 root id

题意:维护一棵树,某些点有点权(没有则为正无穷),点权为正整数,查询树上路径点权小于等于某个值的点的个数。

分析:考虑维护主席树,root[i]数组存储第i个节点到根的点权的权值线段树的树根。更具体地,把第i个节点到根的路径上的点权累积到权值线段树中,对一个询问x,y,记lca为z,查询值为k,答案ans=que(root[x],root[fa[z]],1,m,k)+que(root[y],root[fa[z]],1,m,k)-que(root[z],root[fa[z]],1,m,k)

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+100;
inline int read()
{
    register char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return x*f;
}
struct edge{int y,n;}e[N<<1];
struct ques{int x,y,z,opt,id;}q[N<<1];
struct segtree{int lc,rc;int val;}s[N<<7];
int n,m,rot;
int st[N][23],dep[N];
int head[N],cnt;
int root[N],tot,dfn[N],tim,rk[N],mod,num=1;
int ans[N],siz[N];
void ad(int x,int y){e[++cnt].n=head[x];e[cnt].y=y;head[x]=cnt;}
void go(int u,int fa)
{
    dep[u]=dep[fa]+1;st[u][0]=fa;rk[u]=++tim;
    for(int i=1;i<=18;++i)st[u][i]=st[st[u][i-1]][i-1];
    for(int i=head[u];i;i=e[i].n)go(e[i].y,u);
}
bool cmp(ques c,ques d){return c.opt>d.opt;}
bool mcp(ques c,ques d){return rk[c.x]<rk[d.x];}
int lca(int x,int y)
{
    if(x==y)return x;
    if(dep[x]<dep[y])swap(x,y);
    for(int i=18;i>=0;--i)
        if(dep[st[x][i]]>=dep[y])
            x=st[x][i];
    if(x==y)return x;
    for(int i=18;i>=0;--i)
        if(st[x][i]!=st[y][i])
        x=st[x][i],y=st[y][i];
    return st[x][0];
}
void init()
{
    n=read();//1~n
    for(int i=1;i<=n;++i)
    {
        int x=read();
        if(x!=0)
        ad(x,i);
        else
        rot=i;
    }
    go(rot,0);
    m=read();
    for(int i=1;i<=m;++i)
    {
        q[i].opt=read();
        q[i].x=read();
        q[i].id=i;
        if(q[i].opt==1)
        {
            ++mod;
            q[i].y=read();
            q[i].z=read();
        }
    }

}
void build(int &i,int l,int r)
{
    if(!i)i=++tot;
    if(l==r)return ;int mid=(l+r)>>1;
    build(s[i].lc,l,mid);build(s[i].rc,mid+1,r);
}
void upd(int &i,int id,int l,int r,int x,int z)
{
    if(!i)i=++tot;
    s[i].val=s[id].val+z;
    if(l==r && l==x)return ;int mid=(l+r)>>1;
    if(x<=mid){s[i].rc=s[id].rc;upd(s[i].lc,s[id].lc,l,mid,x,z);}
    else {s[i].lc=s[id].lc;upd(s[i].rc,s[id].rc,mid+1,r,x,z);}
}
void rep(int u)//maybe wrong
{
    if(num<=m-mod && q[num].x==u)
    upd(root[u],root[st[u][0]],1,m,q[num++].id,1);
    else root[u]=root[st[u][0]];
    /*
        former wrong:
        while(q[num].x==u && num<=m-mod)
            upd(root[u],root[st[u][0]],1,m,q[num++].id,1);
    */
    for(int i=head[u];i;i=e[i].n)rep(e[i].y);
}
int que(int i,int id,int l,int r,int x)
{
    int mid=(l+r)>>1;
    if(r<=x)return s[i].val-s[id].val;
    if(x>mid)
        return que(s[i].rc,s[id].rc,mid+1,r,x)+s[s[i].lc].val-s[s[id].lc].val;
    return que(s[i].lc,s[id].lc,l,mid,x);
}
void work()
{
    build(root[0],1,m);
    sort(q+1,q+1+m,cmp);
    sort(q+1,q+1+m-mod,mcp);rep(rot);
    for(int i=1;i<=m;++i)ans[i]=-1;
    for(int i=m-mod+1;i<=m;++i)
    {
        int x=q[i].x,y=q[i].y,z=q[i].z;
        int zu=lca(x,y),pre=0,bak=0,pot=0;
        if(q[i].id-z-1>0)
        {
            pre=que(root[x],root[st[zu][0]],1,m,q[i].id-z-1);
            bak=que(root[y],root[st[zu][0]],1,m,q[i].id-z-1);
            pot=que(root[zu],root[st[zu][0]],1,m,q[i].id-z-1);
        }
        ans[q[i].id]=pre+bak-pot;
        siz[q[i].id]=dep[x]+dep[y]-2*dep[st[zu][0]]-1;
    }

    for(int i=1;i<=m;++i)
        if(ans[i]!=-1)printf("%d %d\n",siz[i],ans[i]);
}
int main()
{
    freopen("intelligence.in","r",stdin);
    freopen("intelligence.out","w",stdout);
    init();
    work();
    return 0;
}

标签:return,int,st,P4216,que,SCOI2015,树上,root,id
From: https://www.cnblogs.com/Glowingfire/p/18374661

相关文章

  • 【题解】Solution Set - NOIP2024集训Day12 树上启发式合并
    【题解】SolutionSet-NOIP2024集训Day12树上启发式合并https://www.becoder.com.cn/contest/5472「CF600E」Lomsatgelral直接dsuontree。记录每一个颜色的出现次数。「IOI2011」Race之前是用点分治做的。考虑dsuontree。每个子树内维护到根节点的距离为\(x\)......
  • 树上游戏(树类型题目思考题)
    第2题   树上游戏 查看测评数据信息有一棵n个节点的树。T站在u号节点上,A站在v号节点上。现在,两个人轮流移动,T是先手。每人每次移动必须移动到任何一个相邻的节点。如果某个人发现自己与对方站在了同一个节点上,那么宣布游戏结束。注意每个人每一轮必须移动。已知T希望游戏......
  • lg树上操作
    lg树上操作P3258树上差分P1600[NOIP2016]天天爱跑步分开两边处理。对于上升段,如果一个点深度是x=dep_i+w_i,那么i就被贡献我们可以将整个上升段的x位置都加,然后在每个点处统计dep_i+w_i位置的值。每个点开一个vector记录修改操作。不过这样可能会有互相影响......
  • 树上合并 目前的总结
    启发式合并(set)元素少的set中的元素一一插入元素多的set中。时间两只\(\log\)。空间最坏为\(n\)这个级别(结点数)(这是在默认一个结点最多增加一个元素的情况下)。log数据结构时间也是两只\(\log\)。dsuontree好像[也叫“树上启发式合并”](??)。[一般](?)是重链剖分一样划分......
  • C240817D. 模拟赛:树上dp(以i为起点)+set操作
    C240817D.模拟赛比较显然的树上dp,但是维护set比较烦考场上其实自己是定义\(f[i]\)是以\(i\)结尾,然后这样的话单次更新根本做不到\(O(logN)\).反应实在是太迟钝了,考场想“如果有一种只更新一条链的dp就好了”结果完全没想到只需变成以\(i\)开头就行了.积累经验吧。......
  • 树上计数2
    树上莫队通过将树转化成DFS序(欧拉序)来解决问题。这道题目跟“HH的项链”很像,考虑树上莫队首先对树做出一个欧拉序,得到每个点在欧拉序中第一次出现的位置in[x]和第二次出现的位置out[x];如果某个询问的\((x,y)\)的in[x]比in[y]大,那么交换\(x,y\),下面假设in[x]比in[y]小如果\(x,y\)......
  • 2024杭电多校第十场 1002树上询问(题解)
    题意给一棵树,每个节点有一个权值,并且权值是一个排列。接下来有多次操作,每次操作要么是交换两个节点权值,要么是询问一个权值区间\([L,R]\),判断是否存在树上的一个路径,使得路径上的权值恰好都在这个区间里分析由于询问的是树上的一个路径,联想到了树上莫队中对路径的处理。这里......
  • 【树上点差分、LCA】Max Flow P
    核心思路[USACO15DEC]MaxFlowP-洛谷sum[u]++,sum[v]++,sum[lca(u,v)]--,sum[fa[lca(u,v)]];本质上就是,对树进行差分自底向上进行统计处理#include<bits/stdc++.h>usingnamespacestd;intn,m;constintN=200000+10;vector<int>G[N];intdep[N],fa[N],hs......
  • P5836 [USACO19DEC] Milk Visits S(树上并查集)
    核心思路对于相同颜色且相邻的点合并。若不在同一集合,则0若在同一集合,同色1异色0AC代码#include<bits/stdc++.h>usingnamespacestd;intfa[1145141];charcol[1145141];intn,m;intfind(intx){ if(x==fa[x]) returnx; returnfa[x]=find(fa[x]);}v......
  • P4155 [SCOI2015] 计划
    [SCOI2015]计划-洛谷核心思路注意到,可推出, 表示战士 走  步到达战士位置。若可以走到且r<终点则答案+ 然后再加上自己这个哨兵,和走回自己的一个哨兵即可。AC代码#include<bits/stdc++.h>usingnamespacestd;constintN=2e6+9;intgo[N][22]......