SDOI2014 旅行 动态开点线段树

写的指针比较慢 自带巨大常数 在BZOJ和洛谷都tle了
卡卡常就A了
宛如智障一般在可以 直接判断大小然后swap的地方 声明了两个int来进行区间修改 于是光荣tle
没有写内存回收 删除操作直接把原来所在树上的权值设为0了 并没有删内存

#include<cstdio>
#include<cstring>
#include<algorithm> 
#include<queue>
using namespace std;
#define Max(_A,_B) (_A>_B?_A:_B)
#define Swap(_A,_B) (_A^=_B^=_A^=_B)
#define Min(_A,_B) (_A<_B?_A:_B)
#define Abs(_A) (_A>0?_A:(-_A))
#define ll long long
const int maxn=100007; 
struct Node{
    int mx,w;
    Node *ls,*rs;
    void pushup(){
        w=mx=0; 
        if(ls!=NULL) {
            w+=ls->w;
            mx=Max(mx,ls->mx);
        }
        if(rs!=NULL){
            w+=rs->w;
            mx=Max(mx,rs->mx);
        }
    }  
}pool[maxn<<4],*root[maxn];

Node *newNode(){
    static int cnt=0;
    return pool+cnt++;
}

void modify(Node* &cur,int l,int r,int x,int v){
        //把x点的w改为v
        if(cur==NULL) cur=newNode();
        if(l==r) {
            cur->w=cur->mx=v;
            return;
        }
        int mid=(l+r)>>1;
        (x<=mid)?modify(cur->ls,l,mid,x,v):modify(cur->rs,mid+1,r,x,v);
        cur->pushup();
}
int queryw(Node* &cur,int l,int r,int x,int y){
        if(cur==NULL)  return 0;
        if(x<=l&&r<=y) return cur->w;
        int mid=(l+r)>>1;
        if(x<=mid&&y>mid) return queryw(cur->ls,l,mid,x,y)+queryw(cur->rs,mid+1,r,x,y);
        if(x<=mid) return queryw(cur->ls,l,mid,x,y);
        if(y>mid) return queryw(cur->rs,mid+1,r,x,y);
}
int querymx(Node* &cur,int l,int r,int x,int y){
        if(cur==NULL) return 0;
        if(x<=l&&r<=y) return cur->mx;
        int mid=(l+r)>>1,res=0;
        if(x<=mid&&y>mid) return Max(querymx(cur->ls,l,mid,x,y),querymx(cur->rs,mid+1,r,x,y));
        if(x<=mid) return querymx(cur->ls,l,mid,x,y);
        if(y>mid) return querymx(cur->rs,mid+1,r,x,y);
}

/*指针实现线段树 资瓷动态开点 单点修改 
区间最值查询 区间和查询*/

/*树链剖分*/
struct edge{
    int v,nxt;
}e[maxn<<1];
int head[maxn],eid=0,dfl[maxn],fa[maxn],
w[maxn],c[maxn],top[maxn],siz[maxn],
son[maxn],dep[maxn],tot,n;

void insert(int u,int v){// 无向边 
    e[++eid].v=v;e[eid].nxt=head[u];head[u]=eid;
    e[++eid].v=u;e[eid].nxt=head[v];head[v]=eid;
}
void dfs1(int u){
    siz[u]=1;
    int i,v;
    for(i=head[u];i;i=e[i].nxt){
        v=e[i].v;
        if(v!=fa[u]){
            dep[v]=dep[u]+1;
            fa[v]=u;
            dfs1(v);
            siz[u]+=siz[v];
            if(siz[v]>siz[son[u]]) 
                son[u]=v;
        }
    }
}

void dfs2(int u,int t){
    dfl[u]=++tot;
    top[u]=t; 
    if(son[u]){
        int i,v;
        dfs2(son[u],t);
        for(i=head[u];i;i=e[i].nxt){
            v=e[i].v;
            if(v!=fa[u]&&v!=son[u]){
                dfs2(v,v);
            }
        }
    }
}

int lca(int x,int y){
    while(top[x]^top[y]){
        if(dep[top[x]]<dep[top[y]])
            Swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}

int solvew(int x,int y,int c){
    //查询颜色为c的线段树
    int res=0;
    while(top[x]^top[y]){
        if(dep[top[x]]<dep[top[y]]) Swap(x,y);
        res+=queryw(root[c],1,tot,dfl[top[x]],dfl[x]);
        x=fa[top[x]];
    } 
    if(dep[x]<dep[y]) Swap(x,y);
    res+=queryw(root[c],1,tot,dfl[y],dfl[x]);
    return res;
}

int solvemx(int x,int y,int c){
    int res=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) Swap(x,y);
        res=Max(res,querymx(root[c],1,tot,dfl[top[x]],dfl[x]));
        x=fa[top[x]];
    }
    if(dep[x]<dep[y]) Swap(x,y);
    res=Max(res,querymx(root[c],1,tot,dfl[y],dfl[x]));
    return res;
}

int read(){
    char c;int s=0;bool f=1;
    while(c=getchar(),(c<'0'||c>'9')&&c!='-');
    c=='-'?f=0:s=c-'0';
    while(c=getchar(),(c>='0'&&c<='9'))
    s=s*10+c-'0';
    return s;
}

int q,u,v,i;
char str[10];
int main(){
    //init(); 
    n=read();q=read();
    for(i=1;i<=n;i++){
        w[i]=read();c[i]=read();
    }
    for(i=1;i<n;i++){
        u=read();v=read();
        insert(u,v);
    }
    dfs1(1);
    dfs2(1,1);
    for(i=1;i<=n;i++){
        modify(root[c[i]],1,n,dfl[i],w[i]);
    }
    while(q--){
        scanf("%s",str);
        u=read();v=read();
        switch(str[1]){
            case 'C':modify(root[c[u]],1,n,dfl[u],0);
            c[u]=v;modify(root[c[u]],1,n,dfl[u],w[u]);
            break;
            //城市u的居民改C教 
            case 'W'://城市u的评级调整为v
            w[u]=v; 
            modify(root[c[u]],1,n,dfl[u],w[u]);
            break;
            case 'S':
            //查询评级总和
            printf("%d\n",solvew(u,v,c[u]));
            break;
            default:
            printf("%d\n",solvemx(u,v,c[u]));
            break; 
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值