LibreOJ #6208. 树上询问

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LibreOJ #6208. 树上询问相关的知识,希望对你有一定的参考价值。

                        内存限制:512 MiB 时间限制:500 ms 标准输入输出
                            题目类型:传统 评测方式:文本比较
                                 上传者: 匿名

树链剖分+线段树

屠龙宝刀点击就送

#include <vector>
#include <cstdio>
#define N 100005
using namespace std;
vector<int>G[N];
struct Segment
{
    int l,r,mid,t,ki,k,flagk,flagt;
    Segment * ch[2];
    Segment ()
    {
        t=ki=k=flagk=flagt=0;
        ch[0]=ch[1]=NULL;
    }
}*root=new Segment;
int n,m,tim,top[N],siz[N],dep[N],fa[N],belong[N];
void dfs1(int x)
{
    siz[x]=1;
    dep[x]=dep[fa[x]]+1;
    for(int i=0;i<G[x].size();++i)
    {
        int v=G[x][i];
        if(fa[x]==v) continue;
        fa[v]=x;
        dfs1(v);
        siz[x]+=siz[v];
    }
}
void dfs2(int x)
{
    if(!top[x]) top[x]=x;
    int p=0;
    belong[x]=++tim;
    for(int i=0;i<G[x].size();++i)
    {
        int v=G[x][i];
        if(fa[x]!=v&&siz[p]<siz[v]) p=v;
    }
    if(p) top[p]=top[x],dfs2(p);
    for(int i=0;i<G[x].size();++i)
    {
        int v=G[x][i];
        if(fa[x]!=v&&v!=p) dfs2(v);
    }
}
void build(Segment *&k,int l,int r)
{
    k=new Segment;
    k->l=l;k->r=r;
    if(l==r) return;
    k->mid=(l+r)>>1;
    build(k->ch[0],l,k->mid);
    build(k->ch[1],k->mid+1,r);
}
void pushdown(Segment *&k)
{
    k->ch[0]->t+=k->t+k->flagt*k->ch[0]->k;
    k->ch[1]->t+=k->t+k->flagt*k->ch[1]->k;
    k->ch[0]->ki+=k->flagk;
    k->ch[1]->ki+=k->flagk;
    k->ch[0]->flagk+=k->flagk;
    k->ch[1]->flagk+=k->flagk;
    k->ch[0]->flagt+=k->flagt;
    k->ch[1]->flagt+=k->flagt;
    k->flagk=0;
    k->flagt=0;
    k->t=0;
}
void plusk(Segment *&k,int l,int r,int d)
{
    if(k->l==l&&k->r==r) {k->ki+=d;k->k+=d;k->flagk+=d;return;}
    pushdown(k);
    if(l>k->mid) plusk(k->ch[1],l,r,d);
    else if(r<=k->mid) plusk(k->ch[0],l,r,d);
    else plusk(k->ch[0],l,k->mid,d),plusk(k->ch[1],k->mid+1,r,d);
}
void plust(Segment *&k,int l,int r,int d)
{
    if(k->l==l&&k->r==r) {k->t+=d*k->ki;k->flagt+=d;return;}
    pushdown(k);
    if(l>k->mid) plust(k->ch[1],l,r,d);
    else if(r<=k->mid) plust(k->ch[0],l,r,d);
    else plust(k->ch[0],l,k->mid,d),plust(k->ch[1],k->mid+1,r,d);
}
int query(Segment *&k,int t)
{
    if(k->l==k->r) return k->t;
    pushdown(k);
    if(t<=k->mid) return query(k->ch[0],t);
    else return query(k->ch[1],t);
}
void solvek(int x,int y,int d)
{
    for(;top[x]!=top[y];x=fa[top[x]])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        plusk(root,belong[top[x]],belong[x],d);
    }
    if(dep[x]<dep[y]) swap(x,y);
    plusk(root,belong[y],belong[x],d);
}
void solvet(int x,int y,int d)
{
    for(;top[x]!=top[y];x=fa[top[x]])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        plust(root,belong[top[x]],belong[x],d);
    }
    if(dep[x]<dep[y]) swap(x,y);
    plust(root,belong[y],belong[x],d);
}
int Main()
{
    scanf("%d",&n);
    for(int u,v,i=1;i<n;++i)
    {
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);  
    }
    dfs1(1);dfs2(1);
    build(root,1,n);
    scanf("%d",&m);
    for(int opt,x,d;m--;)
    {
        scanf("%d%d",&opt,&x);
        if(opt==1) {scanf("%d",&d);if(d) solvek(1,x,d);} 
        else if(opt==2) {scanf("%d",&d);if(d) solvet(1,x,d);} 
        else printf("%d\\n",query(root,belong[x]));
    }
    return 0;
}
int sb=Main();
int main(int argc,char *argv[]){;}

 

以上是关于LibreOJ #6208. 树上询问的主要内容,如果未能解决你的问题,请参考以下文章

「LibreOJ β Round #2」计算几何瞎暴力

libreoj #514. 「LibreOJ β Round #2」模拟只会猜题意

LibreOJ #109. 并查集

LibreOJ 6278. 数列分块入门 2 题解

LibreOJ2097 - 「CQOI2015」任务查询系统

LibreOJ - 6277 数列分块入门 1(分块模板)