POJ3237 Tree(树链剖分 边权)

题目大意:指定一颗树上有3个操作:询问操作,询问a点和b点之间的路径上最长的那条边的长度;取反操作,将a点和b点之间的路径权值都取相反数;变化操作,把某条边的权值变成指定的值。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cstdio>
using namespace std;
const int N=100010;
struct Edge
{
    int to,next;
}eg[N*2];
int head[N],tot;
int top[N];//top[v]表示v所在的重链的顶端节点
int fa[N];//父亲节点
int deep[N];//深度
int num[N];//num[v]表示以v为根的子树的节点数
int p[N];//p[v]表示v与其父亲节点的连边在线段树中的位置
int fp[N];//和p数组相反
int son[N];//重儿子
int pos;
void init()
{
    tot=0;
    memset(head,-1,sizeof(head));
    pos=0;
    memset(son,-1,sizeof(son));
}
void add(int u,int v)
{
    eg[tot].to=v;
    eg[tot].next=head[u];
    head[u]=tot++;
}
void dfs1(int u,int pre,int d)//第一遍dfs求出fa,deep,num,son
{
    deep[u]=d;
    fa[u]=pre;
    num[u]=1;
    for(int i=head[u];i!=-1;i=eg[i].next)
    {
        int v=eg[i].to;
        if(v!=pre)
        {
            dfs1(v,u,d+1);
            num[u]+=num[v];
            if(son[u]==-1||num[v]>num[son[u]]) son[u]=v;
        }
    }
}
void getpos(int u,int sp)//第二遍dfs求出top和p
{
    top[u]=sp;
    p[u]=pos++;
    fp[p[u]]=u;
    if(son[u]==-1) return ;
    getpos(son[u],sp);
    for(int i=head[u];i!=-1;i=eg[i].next)
    {
        int v=eg[i].to;
        if(v!=son[u]&&v!=fa[u]) getpos(v,v);
    }
}
//线段树
struct Node
{
    int l,r,ma,mi,ne;
}tree[N*3];
void build(int i,int l,int r)
{
    tree[i].l=l;
    tree[i].r=r;
    tree[i].ma=tree[i].mi=tree[i].ne=0;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
}
void pushup(int i)
{
    tree[i].mi=min(tree[i<<1].mi,tree[i<<1|1].mi);
    tree[i].ma=max(tree[i<<1].ma,tree[i<<1|1].ma);
}
void pushdown(int i)
{
    if(tree[i].l==tree[i].r) return ;
    if(tree[i].ne)
    {
        tree[i<<1].ma=-tree[i<<1].ma;
        tree[i<<1].mi=-tree[i<<1].mi;
        swap(tree[i<<1].ma,tree[i<<1].mi);
        tree[i<<1|1].ma=-tree[i<<1|1].ma;
        tree[i<<1|1].mi=-tree[i<<1|1].mi;
        swap(tree[i<<1|1].ma,tree[i<<1|1].mi);
        tree[i<<1].ne^=1;
        tree[i<<1|1].ne^=1;
        tree[i].ne=0;
    }
}
void update(int i,int k,int val)//更新线段树的第k个值为val
{
    if(tree[i].l==k&&tree[i].r==k)
    {
        tree[i].ma=tree[i].mi=val;
        tree[i].ne=0;
        return ;
    }
    pushdown(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(k<=mid) update(i<<1,k,val);
    else update(i<<1|1,k,val);
    pushup(i);
}
void ne_update(int i,int l,int r)//更新线段树的区间[l,r]取反
{
    if(tree[i].l==l&&tree[i].r==r)
    {
        tree[i].ma=-tree[i].ma;
        tree[i].mi=-tree[i].mi;
        swap(tree[i].ma,tree[i].mi);
        tree[i].ne^=1;
        return ;
    }
    pushdown(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid) ne_update(i<<1,l,r);
    else if(l>mid) ne_update(i<<1|1,l,r);
    else
    {
        ne_update(i<<1,l,mid);
        ne_update(i<<1|1,mid+1,r);
    }
    pushup(i);
}
int query(int i,int l,int r)//查询线段树中[l,r]的最大值
{
    if(tree[i].l==l&&tree[i].r==r) return tree[i].ma;
    pushdown(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid) return query(i<<1,l,r);
    else if(l>mid) return query(i<<1|1,l,r);
    else return max(query(i<<1,l,mid),query(i<<1|1,mid+1,r));
    pushup(i);
}
int find(int u,int v)//查询u->v边的最大值
{
    int f1=top[u],f2=top[v],tmp=-100000000;
    while(f1!=f2)
    {
        if(deep[f1]<deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        tmp=max(tmp,query(1,p[f1],p[u]));
        u=fa[f1];
        f1=top[u];
    }
    if(u==v) return tmp;
    if(deep[u]>deep[v]) swap(u,v);
    return max(tmp,query(1,p[son[u]],p[v]));
}
void nega(int u,int v)//把u-v路径上的边的值都设置为val
{
    int f1=top[u],f2=top[v];
    while(f1!=f2)
    {
        if(deep[f1]<deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        ne_update(1,p[f1],p[u]);
        u=fa[f1];
        f1=top[u];
    }
    if(u==v) return ;
    if(deep[u]>deep[v]) swap(u,v);
    return ne_update(1,p[son[u]],p[v]);
}
int e[N][3];
int main()
{
    //freopen("in.txt","r",stdin);
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d",&n);
        for(int i=0;i<n-1;i++)
        {
            scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
            add(e[i][0],e[i][1]);
            add(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        build(1,0,pos-1);
        for(int i=0;i<n-1;i++)
        {
            if(deep[e[i][0]]>deep[e[i][1]]) swap(e[i][0],e[i][1]);
            update(1,p[e[i][1]],e[i][2]);
        }
        char op[10];
        int u,v;
        while(scanf("%s",op))
        {
            if(op[0]==‘D‘) break;
            scanf("%d%d",&u,&v);
            if(op[0]==‘Q‘) printf("%d\n",find(u,v));//查询u->v路径上边权的最大值
            else if(op[0]==‘N‘) nega(u,v);
            else update(1,p[e[u-1][1]],v);//修改第u条边的长度为v
        }
    }
    return 0;
}
时间: 2024-08-13 02:44:01

POJ3237 Tree(树链剖分 边权)的相关文章

SPOJ375 Query on a tree 树链剖分

SPOJ375  Query on a tree   树链剖分 no tags You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of

hdu 5242 树链剖分找权值最大的前k条链

http://acm.hdu.edu.cn/showproblem.php?pid=5242 Problem Description It is well known that Keima Katsuragi is The Capturing God because of his exceptional skills and experience in ''capturing'' virtual girls in gal games. He is able to play k games sim

SPOJ - QTREE 375 Query on a tree 树链剖分+线段树

操作1:修改第k条边权. 操作2:询问两点间最大边权. 树链剖分,然后线段树维护最大值 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #inclu

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时... 代码如下: 1 //树链剖分 点权修改 修改单节点 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespa

HDU3966 Aragorn&#39;s Story(树链剖分 点权 模版题)

#include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <map> #include <set> #include <vector> #include <cstdio> using namespace std; const int N=50010; s

【POJ3237】Tree 树链剖分

题意: change,把第i条边权值改成v negate,把a到b路径上所有权值取相反数(*(-1)) query,询问a到b路径上所有权值的最大值 树链剖分. 以前一直不会,但是我恶补LCT了,所以先学一下. 对于现在的水平来说,树剖太水了,自己翻资料吧,我只提供一个还算不错的代码. 扒代码的时候可以用我的这个. 附rand和pai. 代码: #include <cstdio> #include <cstring> #include <iostream> #inclu

spoj 375 Query on a tree (树链剖分)

Query on a tree You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to ti or Q

树链剖分——边上权值和

Queries On Tree Problem code: TAQTREE Tweet All submissions for this problem are available. Read problems statements in Mandarin Chinese and Russian. You are given a tree of N nodes numbered from 1 to N. The ith edge connecting node ui and vi has a w

SPOJ Query on a tree 树链剖分 水题

You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of the i-th edge to tior QUERY a b : ask fo

poj 3237 Tree 树链剖分+线段树

Description You are given a tree with N nodes. The tree's nodes are numbered 1 through N and its edges are numbered 1 through N ? 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions