【POJ3237】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 throughN − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
CHANGE
ivChange the weight of the ith edge to v NEGATE
abNegate the weight of every edge on the path from a to b QUERY
abFind the maximum weight of edges on the path from a to b Input
The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.
Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers a, b and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “
DONE
” ends the test case.Output
For each “
QUERY
” instruction, output the result on a separate line.Sample Input
1 3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONESample Output
1
3
【题意】
指定一颗树上有3个操作:
询问操作,询问a点和b点之间的路径上最长的那条边的长度;
取反操作,将a点和b点之间的路径权值都取相反数;
变化操作,把某条边的权值x变成指定的值。
【分析】
人生第一道树剖题,调了好久啊,200+的代码还打了对拍= =
就是裸的树链剖分+线段树啦。
就是线段树打得不够熟练所以调了那么久,lazy标记不大会用~~
树剖的主要过程就是两次的dfs,第一次求fa,第二次求top。询问过程就是一直跳,跳到两个东西在一条重链上去。
因为某种特殊性质,所以他很快。。
代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 10010
#define INF 100000000 int fa[Maxn],first[Maxn],size[Maxn],dep[Maxn],son[Maxn];
int w[Maxn],top[Maxn];int wl;
int b[Maxn][]; struct node
{
int x,y,c,next;
}t[*Maxn];int len; struct nnode
{
int l,r,lc,rc,mx,mn;
bool lazy;
}tr[*Maxn];int tl; int mymax(int x,int y) {return x>y?x:y;}
int mymin(int x,int y) {return x<y?x:y;} void ins(int x,int y,int c)
{
t[++len].x=x;t[len].y=y;t[len].c=c;
t[len].next=first[x];first[x]=len;
} void dfs1(int x,int f)
{
fa[x]=f;dep[x]=dep[f]+;size[x]=;
son[x]=;
for(int i=first[x];i;i=t[i].next) if(t[i].y!=f)
{
dfs1(t[i].y,x);
size[x]+=size[t[i].y];
if(size[t[i].y]>size[son[x]]) son[x]=t[i].y;
}
} void dfs2(int x,int tp)
{
w[x]=++wl;
top[x]=tp;
if(size[x]!=) dfs2(son[x],tp);
for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x]&&t[i].y!=son[x])
{
dfs2(t[i].y,t[i].y);
}
} int build(int l,int r)
{
int x=++tl;
tr[x].l=l;tr[x].r=r;tr[x].mx=-INF;tr[x].mn=INF;tr[x].lazy=;
if(l!=r)
{
int mid=(l+r)>>;
tr[x].lc=build(l,mid);
tr[x].rc=build(mid+,r);
}
return x;
} void upd(int x)
{
if(!tr[x].lazy) return;
tr[x].lazy=;
int a=tr[x].mx;
tr[x].mx=-tr[x].mn;tr[x].mn=-a;
if(tr[x].l==tr[x].r) return;
tr[tr[x].lc].lazy=!tr[tr[x].lc].lazy;
tr[tr[x].rc].lazy=!tr[tr[x].rc].lazy;
} void change(int x,int y,int c)
{
upd(x);
if(tr[x].l==tr[x].r)
{
tr[x].mx=c;
tr[x].mn=c;
return;
}
int mid=(tr[x].l+tr[x].r)>>;
if(y<=mid) change(tr[x].lc,y,c);
else change(tr[x].rc,y,c);
upd(tr[x].lc);upd(tr[x].rc);
tr[x].mx=mymax(tr[tr[x].lc].mx,tr[tr[x].rc].mx);
tr[x].mn=mymin(tr[tr[x].lc].mn,tr[tr[x].rc].mn);
} int qtree(int x,int l,int r)
{
upd(x);
if(tr[x].l==l&&tr[x].r==r) return tr[x].mx;
int mid=(tr[x].l+tr[x].r)>>;
if(r<=mid) return qtree(tr[x].lc,l,r);
if(l>mid) return qtree(tr[x].rc,l,r);
return mymax(qtree(tr[x].lc,l,mid),qtree(tr[x].rc,mid+,r));
} int query(int x,int y)
{
int tmp=-INF;
int f1=top[x],f2=top[y];
while(f1!=f2)
{
if(dep[f1]<dep[f2])
{
swap(f1,f2);
swap(x,y);
}
tmp=mymax(qtree(,w[f1],w[x]),tmp);
x=fa[f1];
f1=top[x];
}
if(x==y) return tmp;
if(dep[x]<dep[y]) swap(x,y);
return mymax(tmp,qtree(,w[son[y]],w[x]));
} void change2(int x,int l,int r)
{
upd(x);
if(tr[x].l==l&&tr[x].r==r)
{
tr[x].lazy=!tr[x].lazy;
upd(x);
return;
}
int mid=(tr[x].l+tr[x].r)>>;
if(r<=mid) change2(tr[x].lc,l,r);
else if(l>mid) change2(tr[x].rc,l,r);
else
{
change2(tr[x].lc,l,mid);
change2(tr[x].rc,mid+,r);
}
upd(tr[x].lc);upd(tr[x].rc);
tr[x].mx=mymax(tr[tr[x].lc].mx,tr[tr[x].rc].mx);
tr[x].mn=mymin(tr[tr[x].lc].mn,tr[tr[x].rc].mn);
} void negate1(int x,int y)
{
int f1=top[x],f2=top[y];
while(f1!=f2)
{
if(dep[f1]<dep[f2])
{
swap(f1,f2);
swap(x,y);
}
change2(,w[f1],w[x]);
x=fa[f1];
f1=top[x];
}
if(x==y) return;
if(dep[x]<dep[y]) swap(x,y);
change2(,w[son[y]],w[x]);
} int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
memset(first,,sizeof(first));
len=;
for(int i=;i<n;i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
b[i][]=x;b[i][]=y;b[i][]=c;
ins(x,y,c);ins(y,x,c);
}
dep[]=;size[]=;
dfs1(,);wl=;
dfs2(,);
char s[];
tl=;
build(,wl);
for(int i=;i<n;i++)
{
if(dep[b[i][]]<dep[b[i][]]) swap(b[i][],b[i][]);
change(,w[b[i][]],b[i][]);
}
while()
{
scanf("%s",s);
if(s[]=='D') break;
if(s[]=='Q')
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y));
}
else if(s[]=='C')
{
int x,y;
scanf("%d%d",&x,&y);
change(,w[b[x][]],y);//单点修改
}
else
{
int x,y;
scanf("%d%d",&x,&y);
negate1(x,y);
}
}
}
return ;
}
[POJ3237]
2016-05-08 14:50:31
【POJ3237】Tree(树链剖分+线段树)的更多相关文章
- POJ3237 Tree 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- 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 ...
- 【CF725G】Messages on a Tree 树链剖分+线段树
[CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...
- Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
- Water Tree CodeForces 343D 树链剖分+线段树
Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- B20J_3231_[SDOI2014]旅行_树链剖分+线段树
B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
随机推荐
- 【转】C++:在程序中获取全球唯一标识号(GUID或UUID)
Windows:使用CoCreateGuid函数(GUID) #include <objbase.h> #include <stdio.h> #define GUID_LEN ...
- Windows Server 2008中关闭事件跟踪程序的方法
Windows Server 2008跟Windows Server 2003一样,在关机的时候会弹出一个“关闭事件跟踪程序”窗口,当然微软这么做是处于安全的考虑啦,但是如果我们只是个人用用的话,那就 ...
- 如何在OpenWRT环境下做开发
1.搭建开发环境 首先,在执行make menuconfig后,会出现下图: 其中,图中红框部分是我定制路由器的系统版本,大家可以根据不同的路由器进行不同的选择:绿框部分表示我们需要编译一个SDK开发 ...
- andriod 中设置sdk升级代理服务器
Android SDK 在线更新镜像服务器资源: 大连东软信息学院镜像服务器地址: http://mirrors.neusoft.edu.cn 端口:80 北京化工大学镜像服务器地址: IPv4: h ...
- iOS8 iPad Warning: Attempt to present <UIImagePickerController:xxxx > on xxxx which is already presenting (null)
解决方法: /* I think this is because in iOS 8, alert views and action sheets are actually presented view ...
- Linux 中查看网口流量的利器 -- sar
Linux 中查看网口流量的利器 -- sar 有这么一个小工具,通过它能够查看各个网口的IP报文流量统计. 利用sar命令,加上-n DEV参数,即可统计出所有网卡上的流量,在显示的第五和第六列 ...
- LINUX 压缩目录成一个压缩文件
#!/bin/bash file =$(date +%y%m%d%H%M)logfile=/home/目录名/backup/file.log echo "------"$(date ...
- Python转码问题
在Python中,可以对String调用decode和encode方法来实现转码. 比如,若要将某个String对象s从gbk内码转换为UTF-8,可以如下操作 s.decode('gbk').e ...
- U盘安装ubuntu时出现的gfxboot.c32:not a COM32R image问题
方法特别简单:只需在提示后面输入 live 然后回车 就OK了
- [Machine Learning] Probabilistic Graphical Models:一、Introduction and Overview(1、Overview and Motivation)
一.PGM用来做什么 1. 医学诊断:从各种病症分析病人得了什么病,该用什么手段治疗 2. 图像分割:从一张百万像素级的图片中分析每个像素点对应的是什么东西 两个共同点:(1)有非常多不同的输入变 ...