【BZOJ3531】【Sdoi2014】旅行 树链剖分。

广告:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44026729");
}

题解:

开10W棵线段树,然后节点动态加。

然后对于单独线段树树剖。

天哪!!CFree竟然吞了我一个’&’符号。

恶心死了找了正经好一会。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 101000
#define LOGN 20
#define ls s[note].l
#define rs s[note].r
#define inf 0x3f3f3f3f
using namespace std;
struct KSD
{
    int v,next;
}e[N<<1];
int head[N],cnt;
inline void add(int u,int v)
{
    e[++cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
int n,m;
int crs[N],src[N];

int dep[N],top[N],pos[N];
int fa[N],son[N];
int dfs1(int x,int p)
{
    int i,v,temp,mx=0,size=1;
    dep[x]=dep[p]+1;
    fa[x]=p;
    for(i=head[x];i;i=e[i].next)
    {
        v=e[i].v;
        if(v==p)continue;
        temp=dfs1(v,x);
        size+=temp;
        if(mx<temp)mx=temp,son[x]=v;
    }
    return size;
}
void dfs2(int x,int p,int t)
{
    top[x]=t;
    pos[x]=++cnt;
    int i,v;
    if(son[x])dfs2(son[x],x,t);
    for(i=head[x];i;i=e[i].next)
    {
        v=e[i].v;
        if(v==son[x]||v==p)continue;
        dfs2(v,x,v);
    }
}
struct Segment_Tree
{
    int l,r;
    int mx,sum;
}s[N*LOGN*5];
int root[N],num;
inline void pushup(int note)
{
    s[note].mx=max(s[ls].mx,s[rs].mx);
    s[note].sum=s[ls].sum+s[rs].sum;
}
void add(int &note,int L,int R,int x,int w)
{
    if(!note)note=++num;
    if(L==R)
    {
        s[note].mx=s[note].sum=w;
        return ;
    }
    int mid=L+R>>1;
    if(x<=mid)add(ls,L,mid,x,w);
    else add(rs,mid+1,R,x,w);
    pushup(note);
}
void remove(int note,int L,int R,int x)
{
    //if(!note)note=++num;
    if(L==R)
    {
        s[note].mx=s[note].sum=0;
        return ;
    }
    int mid=L+R>>1;
    if(x<=mid)remove(ls,L,mid,x);
    else remove(rs,mid+1,R,x);
    pushup(note);
}
int query(int note,int L,int R,int l,int r,int f)
{
    if(!note)return 0;
    if(L==l&&r==R)
    {
        if(f)return s[note].mx;
        else return s[note].sum;
    }
    int mid=L+R>>1;
    if(r<=mid)return query(ls,L,mid,l,r,f);
    else if(l>mid)return query(rs,mid+1,R,l,r,f);
    else {
        int a=query(ls,L,mid,l,mid,f);
        int b=query(rs,mid+1,R,mid+1,r,f);
        if(f)return max(a,b);
        else return a+b;
    }
}
int QUERY(int a,int b,int f)
{
    int rt=root[crs[a]];
    int ans=0,temp;
    for(int A=top[a],B=top[b];A!=B;a=fa[A],A=top[a])
    {
        if(dep[A]<dep[B])swap(A,B),swap(a,b);
        temp=query(rt,1,n,pos[A],pos[a],f);
        if(f)ans=max(ans,temp);
        else ans+=temp;
    }
    if(dep[a]<dep[b])swap(a,b);
    temp=query(rt,1,n,pos[b],pos[a],f);
    if(f)ans=max(ans,temp);
    else ans+=temp;
    return ans;
}

char ss[5];
int main()
{
    freopen("test.in","r",stdin);
    int i,j,k;
    int a,b,c;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)scanf("%d%d",&src[i],&crs[i]);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    cnt=0;
    dfs1(1,0),dfs2(1,0,1);
    for(i=1;i<=n;i++)add(root[crs[i]],1,n,pos[i],src[i]);
    while(m--)
    {
        scanf("%s%d%d",ss,&a,&b);
        if(ss[1]==‘C‘)
        {
            remove(root[crs[a]],1,n,pos[a]);
            add(root[b],1,n,pos[a],src[a]);
            crs[a]=b;
        }
        else if(ss[1]==‘W‘)
        {
            add(root[crs[a]],1,n,pos[a],b);
            src[a]=b;
        }
        else if(ss[1]==‘S‘)printf("%d\n",QUERY(a,b,0));
        else printf("%d\n",QUERY(a,b,1));
    }
    return 0;
}
时间: 2024-10-29 03:26:59

【BZOJ3531】【Sdoi2014】旅行 树链剖分。的相关文章

BZOJ3531 SDOI2014 旅行 - 树链剖分,主席树

题意:给定一棵树,树上每个点有权值和类型.支持:修改某个点的类型:修改某个点的权值:询问某条链上某个类型的点的和/最大值.点数/类型数/询问数<=100000. 分析: 树链剖分,对每个类型的点建立线段树(动态开点). note: 忘记写t_query返回值调半天-- 莫名其妙地1A 代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int a[5000005],s[5000005],dep[100005],size[10

BZOJ 3531 SDOI2014 旅行 树链剖分

题目大意:给定一棵树,每一个点有一个权值和一个颜色.多次改变一些点的权值和颜色,多次求一条路径上与起点和终点颜色同样的点的权值和以及权值最大值 每种颜色开一个线段树 动态开节点 每一个点仅仅建一条链 这样空间复杂度是O(nlogn)的 然后就正常树链剖分即可了 #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm>

BZOJ 2157 旅行(树链剖分码农题)

写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v经过的边的权值最小值. 基于边权的树链剖分,放在线段树上变成了区间维护问题了,线段树维护4个量min,max,sum,tag就可以了. # include <cstdio> # include <cstring> # include <cstdlib> # include

【BZOJ 3531】【SDOI 2014】旅行 树链剖分

因为有$10^5$个宗教,需要开$10^5$个线段树. 平时开的线段树是“满”二叉树,但在这个题中代表一个宗教的线段树管辖的区间有很多点都不属于这个宗教,也就不用“把枝叶伸到这个点上”,所以这样用类似主席树的数组动态开点来建立$10^5$个只有几个“树枝”的线段树,维护轻重链就可以了 线段树的$L,R,l,r$弄反了调了好久$QAQ$ $so$ $sad$ #include<cstdio> #include<cstring> #include<algorithm> #d

BZOJ.3531.旅行(树链剖分 动态开点)

题目链接 无优化版本(170行): /* 首先树剖可以维护树上的链Sum.Max 可以对每个宗教建一棵线段树,那这题就很好做了 不过10^5需要动态开点 (不明白为什么nlogn不需要回收就可以 不是每个Insert加log个节点?) 操作修改完更改原数列!盲人..少玩rts.. */ #include<cstdio> #include<cctype> #include<algorithm> #define gc() getchar() #define now node

【块状树】【树链剖分】【线段树】bzoj3531 [Sdoi2014]旅行

离线后以宗教为第一关键字,操作时间为第二关键字排序. <法一>块状树,线下ac,线上tle…… #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> using namespace std; queue<int>q; int f,c; inline void R(int &x){ c=0;f=1;

bzoj 3531 [Sdoi2014]旅行(树链剖分,线段树)

3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 876  Solved: 446[Submit][Status][Discuss] Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰.为了方便,我们用不同的正整数代表 各种宗教,  S国的居民常常旅行.旅行时他们总

【Luogu】P3313旅行(树链剖分)

题目链接 动态开点的树链剖分qwq. 跟小奇的花园一模一样,不做过多讲解. #include<cstdio> #include<cstring> #include<cctype> #include<cstdlib> #include<algorithm> #define maxn 100010 #define mid ((l+r)>>1) #define check(x) if(x==0) x=++tot; using namespa

BZOJ3531: [Sdoi2014]旅行

3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 323  Solved: 192[Submit][Status] Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰.为了方便,我们用不同的正整数代表 各种宗教,  S国的居民常常旅行.旅行时他们总会走最短路,并且为