COJ990 WZJ的数据结构(负十)

暑假出的题,其实是从一道BZOJ的题摘下来的,原题还有换根操作,只能用splay动态维护DFS序列。

恩先放一个之前写的DFS序列(带入栈出栈标记)+线段树版本的:(写得丑请不要介意)

询问O(logn)修改O(logn)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200010;
int n,m,first[maxn],next[maxn],v[maxn],e;
void AddEdge(int a,int b)
{
     v[++e]=b;
     next[e]=first[a];
     first[a]=e;
}
int F[maxn],L[maxn],s[maxn],val[maxn],tot;
void dfs(int x)
{
     F[x]=++tot; s[tot]=1;
     for(int i=first[x];i;i=next[i]) dfs(v[i]);
     L[x]=++tot; s[tot]=-1;
}
typedef long long LL;
LL sumv[maxn*3],addv[maxn*3],sz[maxn*3];
void maintain(int o,int L,int R)
{
     sumv[o]=0;
     if(L<R) sumv[o]=sumv[o<<1]+sumv[(o<<1)|1];
     sumv[o]+=addv[o]*sz[o];
}
void build(int o,int L,int R)
{
     if(L==R) addv[o]=val[L],sz[o]=s[L];
     else
     {
         int M=L+R>>1,lc=o<<1,rc=lc|1;
         build(lc,L,M); build(rc,M+1,R);
         sz[o]=sz[lc]+sz[rc];
     }
     maintain(o,L,R);
}
int ql,qr,va;
LL query(int o,int L,int R,int add)
{
    if(ql<=L&&R<=qr) return sumv[o]+add*sz[o];
    else
    {
        int M=L+R>>1,lc=o<<1,rc=lc|1;
        LL ans=0;
        if(ql<=M) ans+=query(lc,L,M,add+addv[o]);
        if(qr>M) ans+=query(rc,M+1,R,add+addv[o]);
        return ans;
    }
}
void update(int o,int L,int R)
{
     if(ql<=L&&R<=qr) addv[o]+=va;
     else
     {
        int M=L+R>>1,lc=o<<1,rc=lc|1;
        if(ql<=M) update(lc,L,M);
        if(qr>M) update(rc,M+1,R);
    }
    maintain(o,L,R);
}
int main()
{
    int p;
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&p);
        AddEdge(p,i);
    }
    dfs(1);
    for(int i=1;i<=n;i++) scanf("%d",&p),val[L[i]]=val[F[i]]=p;
    build(1,1,n*2);
    scanf("%d",&m);
    char cmd[4];
    while(m--)
    {
       scanf("%s",cmd);
       if(cmd[0]==‘Q‘)
       {
           scanf("%d",&qr);ql=1;qr=F[qr];
           printf("%lld\n",query(1,1,n*2,0));
       }
       else
       {
           scanf("%d%d",&ql,&va);
           qr=L[ql]; ql=F[ql];
           update(1,1,n*2);
       }
    }
    return 0;
}

发现可以用树链剖分做,昨天写了一下,WA掉N发,还是线段树写错了。

询问O(log^2n)修改O(logn)

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
typedef long long ll;
const int maxn=100010;
int n,first[maxn],to[maxn],next[maxn],e;
void AddEdge(int u,int v){to[++e]=v;next[e]=first[u];first[u]=e;}//单向边就可以了
int fa[maxn],siz[maxn],son[maxn];
void dfs(int x)//………………
{
    siz[x]=1;
    for(int i=first[x];i;i=next[i])//因为是单向边,下同
    {
        fa[to[i]]=x;dfs(to[i]);
        siz[x]+=siz[to[i]];
        if(siz[son[x]]<siz[to[i]]) son[x]=to[i];
    }
}
int top[maxn],pos[maxn],mx[maxn],sz;
void build(int x,int tp)//建树时记录DFS序的区间
{
    top[x]=tp;pos[x]=++sz;
    if(son[x]) build(son[x],tp);
    for(int i=first[x];i;i=next[i]) if(to[i]!=son[x]) build(to[i],to[i]);
    mx[x]=sz;//右端点
}
int ql,qr;
ll A[maxn],sumv[maxn*3],addv[maxn*3],val;
ll query(int o,int l,int r,ll add)
{
    if(ql<=l&&r<=qr) return sumv[o]+add*(r-l+1);
    int mid=l+r>>1,lc=o<<1,rc=lc|1;ll ans=0;
    if(ql<=mid) ans+=query(lc,l,mid,add+addv[o]);
    if(qr>mid) ans+=query(rc,mid+1,r,add+addv[o]);
    return ans;
}
void build(int o,int l,int r)
{
    int mid=l+r>>1,lc=o<<1,rc=lc|1;
    if(l==r) sumv[o]=addv[o]=A[l];//注意!
    else
    {
        build(lc,l,mid);build(rc,mid+1,r);
        sumv[o]=sumv[lc]+sumv[rc];
    }
}
void update(int o,int l,int r)
{
    int mid=l+r>>1,lc=o<<1,rc=lc|1;
    if(ql<=l&&r<=qr) addv[o]+=val;
    else
    {
        if(ql<=mid) update(lc,l,mid);
        if(qr>mid) update(rc,mid+1,r);
    }
    sumv[o]=0;
    if(l<r) sumv[o]=sumv[lc]+sumv[rc];////注意叶节点信息,本蒟蒻就在这里WA了N发 TAT
    sumv[o]+=(r-l+1)*addv[o];
}
void query(int x)
{
    ll ans=0;
    while(top[x]!=1)//不停向根节点走
    {
        ql=pos[top[x]];qr=pos[x];ans+=query(1,1,n,0);
        x=fa[top[x]];
    }
    ql=1;qr=pos[x];ans+=query(1,1,n,0);
    printf("%lld\n",ans);
}
int main()
{
    n=read();
    for(int i=2;i<=n;i++) AddEdge(read(),i);
    dfs(1);build(1,1);
    for(int i=1;i<=n;i++) A[pos[i]]=read();
    build(1,1,n);
    int q=read();
    while(q--)
    {
        char tp=getchar();
        while(!isalpha(tp)) tp=getchar();
        int x=read();
        if(tp==‘Q‘) query(x);
        else
        {
            val=read();ql=pos[x];qr=mx[x];
            update(1,1,n);
        }
    }
    return 0;
}

时间: 2024-08-28 17:30:20

COJ990 WZJ的数据结构(负十)的相关文章

COJ 1010 WZJ的数据结构(十) 线段树区间操作

传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1001 WZJ的数据结构(十) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,高效执行以下过程: #include<iostream>using namespace std;const int maxn=100010;int A[maxn];int tp,ql,qr,v;int

COJ 1010 WZJ的数据结构(十) 线段树的地狱

传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1001 WZJ的数据结构(十) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,高效执行以下过程: #include<iostream>using namespace std;const int maxn=100010;int A[maxn];int tp,ql,qr,v;int

COJ 0970 WZJ的数据结构(负三十)树分治

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后

COJ 0981 WZJ的数据结构(负十九)树综合

WZJ的数据结构(负十九) 难度级别:E: 运行时间限制:15000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 WZJ的数据结构中有很多都是关于树的.这让很多练习模板的同学还要找来找去很不爽,于是WZJ跟小伙伴们一块商量如何将这些题汇拢到一块去: WZJ:为了大家简单,我规定一开始是一棵有根树. LZJ:那我一定得加上换根操作喽. XJR:链信息修改,链信息增加,链信息翻倍,维护链信息的最大,最小,总和肯定很好做. CHX:子树信息修改,子树信息增加,子树

COJ WZJ的数据结构(负十八)splay_tree的天堂

WZJ的数据结构(负十八) 难度级别:E: 运行时间限制:100000ms: 运行空间限制:700KB: 代码长度限制:2000000B 试题描述 对于前一段样例: 输入 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目. 第2行包含N个数字,描述初始时的数列. 以下M行,每行一条命令,格式参见问题描述中的表格.为了考察垃圾回收的使用,我们精心准备了多组数据... 输出 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字

COJ966 WZJ的数据结构(负三十四)

WZJ的数据结构(负三十四) 难度级别:C: 运行时间限制:20000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给一棵n个节点的树,请对于形如"u r"的Q个询问, 回答以 u 节点为中心,半径 r 以内的节点中,权值最大的节点的编号是多少.如果有多个节点,返回编号最小的. 输入 共有一组测试数据.第一行包含一个整数 n (1 ≤ n ≤ 10^5),表示节点总数.接下来的一行,包含 n 个数字,表示每个节点的权值 vi (1 ≤ vi ≤ 1

COJ0986:WZJ的数据结构(负十四)

WZJ的数据结构(负十四) 难度级别:D: 运行时间限制:6000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的整数组A,M次操作,操作分两种: 1.1 i j k 每次询问给你i,j,k三个参数,求Ai至Aj中第k小的数. 2.0 x v 每次操作给你x,v两个参数,将A[x]改成v. 输入 第一行为两个正整数N,M.第二行为N个正整数Ai.接下来M行为操作. 输出 对于每个询问输出答案(保证k合法)

COJ968 WZJ的数据结构(负三十二)

WZJ的数据结构(负三十二) 难度级别:D: 运行时间限制:5000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,边上均有权值,每个点上有一盏灯,初始均亮着.请你设计一个数据结构,回答M次操作. 1 x:将节点x上的灯拉一次,即亮变灭,灭变亮. 2 x k:询问当前所有亮灯的节点中距离x第k小的距离(注意如果x亮着也算入). 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi

COJ970 WZJ的数据结构(负三十)

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后