bzoj3531: [Sdoi2014]旅行

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3531

题意:中文题。

分析:如果没有颜色的干扰,那么这题只是一个裸树链剖分,但是有了颜色,而且颜色数还多。我们可以想象一下,我们对于每一种颜色都单独取出它们来,然后将相同的颜色像树链剖分那样建线段树,但是如果我们像普通的那样建显然空间会爆炸,我们可以像主席树一样只建有效节点,这样的话我们最多要在线段树中建出2*10^5个叶子,也就是说2*10^5*logn个节点就行啦,然后每次询问就到对应的颜色的那颗线段树上去查询即可。时间O(nlognlogn)空间(n+q)*logn。

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<vector>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const int INF=1000000010;
const ll MAX=1000000000;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
struct node {
    int l,r,ls,rs,mx,sum;
    node(){}
    node(int l,int r,int ls,int rs,int mx,int sum):l(l),r(r),ls(ls),rs(rs),mx(mx),sum(sum) {}
}tr[50*N];
int tot,u[N],v[2*N],pre[2*N];
void add(int x,int y) {
    v[tot]=y;pre[tot]=u[x];u[x]=tot++;
    v[tot]=x;pre[tot]=u[y];u[y]=tot++;
}
char s[5];
int n,w[N],c[N],col[N];
int fa[N],dep[N],siz[N],son[N],top[N],pos[N];
void dfs1(int x,int y) {
    siz[x]=1;son[x]=0;
    fa[x]=y;dep[x]=dep[y]+1;
    int i,mx=0;
    for (i=u[x];i!=-1;i=pre[i])
    if (v[i]!=y) {
        dfs1(v[i],x);siz[x]+=siz[v[i]];
        if (siz[v[i]]>mx) son[x]=v[i],mx=siz[v[i]];
    }
}
void dfs2(int x,int y) {
    if (son[y]==x) top[x]=top[y];
    else top[x]=x;pos[x]=++tot;
    if (son[x]) dfs2(son[x],x);
    for (int i=u[x];i!=-1;i=pre[i])
    if (v[i]!=y&&v[i]!=son[x]) dfs2(v[i],x);
}
void updata(int x,int po,int ww) {
    if (tr[x].l==tr[x].r) { tr[x].sum=tr[x].mx=ww;return ; }
    int mid=(tr[x].l+tr[x].r)>>1;
    if (po<=mid) {
        if (!tr[x].ls) { tot++;tr[tot]=node(tr[x].l,mid,0,0,0,0),tr[x].ls=tot; }
        updata(tr[x].ls,po,ww);
    } else {
        if (!tr[x].rs) { tot++;tr[tot]=node(mid+1,tr[x].r,0,0,0,0),tr[x].rs=tot; }
        updata(tr[x].rs,po,ww);
    }
    tr[x].mx=max(tr[tr[x].ls].mx,tr[tr[x].rs].mx);
    tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;
}
void change(int co,int po,int ww) {
    if (!col[co]) { tr[++tot]=node(1,n,0,0,0,0);col[co]=tot; }
    updata(col[co],po,ww);
}
int statsum(int x,int L,int R) {
    if (x==0||(tr[x].l==L&&tr[x].r==R)) return tr[x].sum;
    int mid=(tr[x].l+tr[x].r)>>1;
    if (R<=mid) return statsum(tr[x].ls,L,R);
    else if (L>mid) return statsum(tr[x].rs,L,R);
    else return statsum(tr[x].ls,L,mid)+statsum(tr[x].rs,mid+1,R);
}
int statmax(int x,int L,int R) {
    if (x==0||(tr[x].l==L&&tr[x].r==R)) return tr[x].mx;
    int mid=(tr[x].l+tr[x].r)>>1;
    if (R<=mid) return statmax(tr[x].ls,L,R);
    else if (L>mid) return statmax(tr[x].rs,L,R);
    else return max(statmax(tr[x].ls,L,mid),statmax(tr[x].rs,mid+1,R));
}
int getsum(int co,int x,int y) {
    int ret=0,f1=top[x],f2=top[y];
    while (f1!=f2) {
        if (dep[f1]<dep[f2]) swap(x,y),swap(f1,f2);
        ret+=statsum(co,pos[f1],pos[x]);
        x=fa[f1];f1=top[x];
    }
    if (dep[x]<dep[y]) swap(x,y);
    ret+=statsum(co,pos[y],pos[x]);
    return ret;
}
int getmax(int co,int x,int y) {
    int ret=0,f1=top[x],f2=top[y];
    while (f1!=f2) {
        if (dep[f1]<dep[f2]) swap(x,y),swap(f1,f2);
        ret=max(ret,statmax(co,pos[f1],pos[x]));
        x=fa[f1];f1=top[x];
    }
    if (dep[x]<dep[y]) swap(x,y);
    ret=max(ret,statmax(co,pos[y],pos[x]));
    return ret;
}
int main()
{
    int i,q,x,y;
    scanf("%d%d", &n, &q);
    tot=0;memset(u,-1,sizeof(u));
    for (i=1;i<=n;i++) scanf("%d%d", &w[i], &c[i]);
    for (i=1;i<n;i++) scanf("%d%d", &x, &y),add(x,y);
    tr[0]=node(0,0,0,0,0,0);
    dfs1(1,0);tot=0;dfs2(1,0);
    for (tot=0,i=1;i<=n;i++) change(c[i],pos[i],w[i]);
    while (q--) {
        scanf("%s%d%d", s, &x, &y);
        if (s[1]=='C') {
            change(c[x],pos[x],0);c[x]=y;change(c[x],pos[x],w[x]);
        } else if (s[1]=='W') {
            change(c[x],pos[x],0);w[x]=y;change(c[x],pos[x],w[x]);
        } else if (s[1]=='S') printf("%d\n", getsum(col[c[x]],x,y));
            else printf("%d\n", getmax(col[c[x]],x,y));
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值