POJ 3237 /// 树链剖分 线段树区间修改(*-1)

题目大意:

给定树的N个结点 编号为1到N 给定N-1条边的边权。

三种操作:

CHANGE k w:将第 k 条边的权值改成 w。

NEGATE x y:将x到y的路径上所有边的权值乘 -1。

QUERY x y:找出x到y的路径上所有边的最大权值。

单点更新 区间更新  区间查询

由于第二个操作是乘 -1 所以需要同时维护最大值和最小值

所以 lazy用来标记是否乘-1 0表示不乘-1 1表示乘-1

http://www.cnblogs.com/HDUjackyan/p/9279777.html

#include <stdio.h>
#include <algorithm>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f
#define mem(i,j) memset(i,j,sizeof(i))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define root 1,n,1

const int maxn=1e4+5;
int n;

struct IntervalTree {
    struct EDGE { int to,ne; }e[maxn<<1];
    int head[maxn], tot;
    void addE(int u,int v) {
        e[tot].to=v;
        e[tot].ne=head[u];
        head[u]=tot++;
    }

    int fa[maxn], son[maxn], dep[maxn], num[maxn];
    int top[maxn], p[maxn], fp[maxn], pos;

    void init() {
        tot=1; mem(head,0);
        pos=0; mem(son,0);
    }

    struct TREE {
        int Max,Min,lazy;
    }tree[maxn<<2];

// --------------------以下是线段树-------------------------

    void pushUp(int rt) {
        tree[rt].Max=max(tree[rt<<1].Max,tree[rt<<1|1].Max);
        tree[rt].Min=min(tree[rt<<1].Min,tree[rt<<1|1].Min);
    }
    void pushDown(int rt,int m) {
        if(m==0) return;
        if(tree[rt].lazy) {
            tree[rt<<1].Max*=-1;
            tree[rt<<1].Min*=-1;
            tree[rt<<1].lazy^=1;
            tree[rt<<1|1].Max*=-1;
            tree[rt<<1|1].Min*=-1;
            tree[rt<<1|1].lazy^=1;
            swap(tree[rt<<1].Max,tree[rt<<1].Min);
            swap(tree[rt<<1|1].Max,tree[rt<<1|1].Min);
            tree[rt].lazy=0;
        }
    }
    void build(int l,int r,int rt) {
        if(l==r) {
            tree[rt].Max=tree[rt].Min=tree[rt].lazy=0;
            return;
        }
        int m=(l+r)>>1;
        build(lson), build(rson);
        pushUp(rt);
    }
    void update1(int k,int w,int l,int r,int rt) {
        if(l==r) {
            tree[rt].Max=tree[rt].Min=w;
            tree[rt].lazy=0;
            return;
        }
        pushDown(rt,r-l+1);
        int m=(l+r)>>1;
        if(k<=m) update1(k,w,lson);
        else update1(k,w,rson);
        pushUp(rt);
    }
    void update2(int L,int R,int l,int r,int rt) {
        if(L<=l && r<=R) {
            tree[rt].Max*=-1;
            tree[rt].Min*=-1;
            tree[rt].lazy^=1;
            swap(tree[rt].Max,tree[rt].Min);
            return ;
        }
        pushDown(rt,r-l+1);
        int m=(l+r)>>1;
        if(L<=m) update2(L,R,lson);
        if(R>m) update2(L,R,rson);
        pushUp(rt);
    }
    int query(int L,int R,int l,int r,int rt) {
        if(L<=l && r<=R) return tree[rt].Max;
        pushDown(rt,r-l+1);
        int m=(l+r)>>1, res=-INF;
        if(L<=m) res=max(res,query(L,R,lson));
        if(R>m) res=max(res,query(L,R,rson));
        pushUp(rt);
        return res;
    }

// --------------------以上是线段树-------------------------

// --------------------以下是树链剖分-------------------------

    void dfs1(int u,int pre,int d) {
        dep[u]=d; fa[u]=pre; num[u]=1;
        for(int i=head[u];i;i=e[i].ne) {
            int v=e[i].to;
            if(v!=fa[u]) {
                dfs1(v,u,d+1);
                num[u]+=num[v];
                if(!son[u] || num[v]>num[son[u]])
                    son[u]=v;
            }
        }
    }
    void dfs2(int u,int sp) {
        top[u]=sp; p[u]=++pos; fp[p[u]]=u;
        if(!son[u]) return;
        dfs2(son[u],sp);
        for(int i=head[u];i;i=e[i].ne) {
            int v=e[i].to;
            if(v!=son[u] && v!=fa[u])
                dfs2(v,v);
        }
    }
    int queryPath(int x,int y) {
        int fx=top[x], fy=top[y], ans=-INF;
        while(fx!=fy) {
            if(dep[fx]>dep[fy]) {
                ans=max(ans,query(p[fx],p[x],root));
                x=fa[fx];
            } else {
                ans=max(ans,query(p[fy],p[y],root));
                y=fa[fy];
            }
            fx=top[x], fy=top[y];
        }
        if(x==y) return ans;
        if(dep[x]>dep[y]) swap(x,y);
        return max(ans,query(p[son[x]],p[y],root));
    }
    void updatePath(int x,int y) {
        int fx=top[x], fy=top[y];
        while(fx!=fy) {
            if(dep[fx]>dep[fy]) {
                update2(p[fx],p[x],root);
                x=fa[fx];
            } else {
                update2(p[fy],p[y],root);
                y=fa[fy];
            }
            fx=top[x], fy=top[y];
        }
        if(x==y) return ;
        if(dep[x]>dep[y]) swap(x,y);
        update2(p[son[x]],p[y],root);
    }

// --------------------以上是树链剖分-------------------------

    void initQTree() {
        dfs1(1,0,0), dfs2(1,1);
        build(root);
    }
}T;
int E[maxn][3];

int main()
{
    int t; scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        T.init();
        for(int i=1;i<n;i++) {
            int u,v,w; scanf("%d%d%d",&u,&v,&w);
            E[i][0]=u, E[i][1]=v, E[i][2]=w;
            T.addE(u,v), T.addE(v,u);
        }
        T.initQTree();
        for(int i=1;i<n;i++) {
            if(T.dep[E[i][0]]>T.dep[E[i][1]])
                swap(E[i][0],E[i][1]); //puts("OK");
            T.update1(T.p[E[i][1]],E[i][2],root);
        }
        while(1) {
            char s[10]; scanf("%s",s);
            if(s[0]==‘D‘) break;
            int x,y; scanf("%d%d",&x,&y);
            if(s[0]==‘Q‘)
                printf("%d\n",T.queryPath(x,y));
            else if(s[0]==‘C‘)
                T.update1(T.p[E[x][1]],y,root);
            else if(s[0]==‘N‘)
                T.updatePath(x,y);
        }
    }

    return 0;
}

原文地址:https://www.cnblogs.com/zquzjx/p/9998751.html

时间: 2024-11-06 09:52:55

POJ 3237 /// 树链剖分 线段树区间修改(*-1)的相关文章

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并

题目描述 由乃正在做她的OJ.现在她在处理OJ上的用户排名问题.OJ上注册了n个用户,编号为1-",一开始他们按照编号 排名.由乃会按照心情对这些用户做以下四种操作,修改用户的排名和编号:然而由乃心情非常不好,因为Deus天 天问她题...因为Deus天天问由乃OI题,所以由乃去学习了一下OI,由于由乃智商挺高,所以OI学的特别熟练她 在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送 Deus:这个题怎么做呀? yuno:这个不是NOI2014的水题吗... Deu

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"."222"和"1". 请你写一个程序依次完成这m个操作. Input 第一行包含2个整数n和m,分别表示节点数和操作数: 第二行包含n个正整数表示n

HDU-3966 Aragorn&#39;s Story(树链剖分+线段树)

Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 12479    Accepted Submission(s): 3331 Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lor

HDU3966 Aragorn&#39;s Story 树链剖分+线段树

区间更新,单点查询,,,,奇葩,HDU上强行加了扩栈才过. 1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 #define lson l,m,rt<<1 8 #define rson m+1,

hdu3966 树链剖分+线段树 裸题

HDU - 3966 题意:给一颗树,3种操作,Q u 查询u节点的权值,I a b c 对a到b的路径上每个点的点权增加c,D a b c 对a b 路径上所有点的点权减少c 思路:树链剖分+线段树,2个问题,第一,如果是先建树再输入点的点权,记录tip(点映射到线段树后的位置),如果先输入点权,再建树,不仅要记录tip还要记录ran(线段树上某个位置上的点对应的树上点的序号,与tip是相互映射):第二,连接起线段树和树链剖分的是get函数,区间操作才需要用到get函数,单点操作直接在线段树上