【poj3237】 Tree
http://poj.org/problem?id=3237 (题目链接)
树链剖分模板题,然而这150+行的程序我调了一天,历经艰辛,终于ac。。
题意
给出一个n个节点的带权树,要求维护操作:1.求出树上两点之间的边权的最大值;2.更改一条边上的权值;3.将树上两点之间的所有边权取各自的相反数。
solution
神奇的树链剖分+线段树维护查询和修改操作。
树链剖分时,我们将每条边的权值转换为除树根外每个节点上的权值(也就是对于每个节点与它父亲的边的权值转换到了自己的权值)。
之后就是标准的树链剖分后跑线段树了,那个全部取相反数的操作其实是一样的,树链剖分相关知识请见http://blog.sina.com.cn/s/blog_7a1746820100wp67.html
编程时请注意细节,邻接表写错了就悲剧了。。
data
#include <ctime>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; int main() {
int i,j,k;
freopen("aaa.in","r",stdin);freopen("aaa.in","w",stdout);
puts("1");
srand((unsigned)time(NULL));
int n=rand()%1000+5;
printf("%d\n",n);
for(i=1;i<n;i++)
printf("%d %d %d\n",i+1,rand()%i+1,rand()%14513546);
for(i=1;i<n;i++) {
int opt=rand()%3;
if(opt==0)
printf("CHANGE %d %d\n",rand()%(n-1)+1,rand()%42534567);
else if(opt==1) {
int a=0,b=0;
while(a==b)a=rand()%n+1,b=rand()%n+1;
printf("NEGATE %d %d\n",a,b);
}
else {
int a=0,b=0;
while(a==b)a=rand()%n+1,b=rand()%n+1;
printf("QUERY %d %d\n",a,b);
}
}
puts("DONE");
fclose(stdin);fclose(stdout);
return 0;
}
代码
// poj3237
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define MOD 1000000007
#define inf 2147483640
#define LL long long
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
inline int getint() {
int x=0,f=1;char ch=getchar();
while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
} const int maxn=100010;
struct edge {int to,next,w;}e[maxn<<2];
struct tree {int l,r,tag,mn,mx;}tr[maxn<<2]; int pos[maxn],deep[maxn],head[maxn],bin[20],fa[maxn][20],size[maxn],to[maxn],bl[maxn];
int cnt,P,n; void insert(int u,int v,int w) {
e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].w=w;
e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;e[cnt].w=w;
}
void solve(int &x,int &y) {
int t=x;x=-y;y=-t;
}
void update(int k)
{
tr[k].mn=min(tr[k<<1].mn,tr[k<<1|1].mn);
tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);
}
void pushdown(int k) {
int l=tr[k].l,r=tr[k].r;
if (l==r || !tr[k].tag) return;
tr[k].tag=0;
tr[k<<1].tag^=1,tr[k<<1|1].tag^=1;
solve(tr[k<<1].mn,tr[k<<1].mx);
solve(tr[k<<1|1].mn,tr[k<<1|1].mx);
}
void build(int k,int s,int t) {
tr[k].l=s,tr[k].r=t,tr[k].tag=0,tr[k].mn=inf,tr[k].mx=-inf;
if (s==t) return;
int mid=(s+t)>>1;
build(k<<1,s,mid);
build(k<<1|1,mid+1,t);
}
void change(int k,int x,int val) {
pushdown(k);
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
if (l==r) {tr[k].mn=tr[k].mx=val;return;}
if (x<=mid) change(k<<1,x,val);
else change(k<<1|1,x,val);
update(k);
}
void rever(int k,int x,int y) {
pushdown(k);
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
if (l==x && r==y) {solve(tr[k].mn,tr[k].mx);tr[k].tag=1;return;}
if (y<=mid) rever(k<<1,x,y);
else if (x>mid) rever(k<<1|1,x,y);
else rever(k<<1,x,mid),rever(k<<1|1,mid+1,y);
update(k);
}
int query(int k,int x,int y) {
pushdown(k);
int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
if (l==x && r==y) return tr[k].mx;
if (y<=mid) return query(k<<1,x,y);
else if (x>mid) return query(k<<1|1,x,y);
else return max(query(k<<1,x,mid),query(k<<1|1,mid+1,y));
}
void dfs1(int x) {
size[x]=1;
for (int i=1;i<=13;i++) {
if (bin[i]<=deep[x]) fa[x][i]=fa[fa[x][i-1]][i-1];
else break;
}
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
deep[e[i].to]=deep[x]+1;
fa[e[i].to][0]=x;
dfs1(e[i].to);
size[x]+=size[e[i].to];
}
}
void dfs2(int x,int chain) {
/*
if (x==22) {
++P;
--P;
}
*/
bl[x]=chain;
pos[x]=++P;
int k=0;
for (int i=head[x];i;i=e[i].next) {
if (e[i].to!=fa[x][0]) {
if (size[e[i].to]>size[k]) k=e[i].to;
}
else {
to[i>>1]=pos[x];//记录每个节点在线段树上的标号
change(1,pos[x],e[i].w);//将权值插入线段树
}
}
if (!k) return;
dfs2(k,chain);
for (int i=head[x];i;i=e[i].next)
if (e[i].to!=fa[x][0] && e[i].to!=k) dfs2(e[i].to,e[i].to);
}
int lca(int x,int y) {
if (deep[x]<deep[y]) swap(x,y);
int t=deep[x]-deep[y];
for (int i=0;i<=13;i++) if (t&bin[i]) x=fa[x][i];
for (int i=13;i>=0;i--)
if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
if (x==y) return x;
return fa[x][0];
}
int solvequery(int x,int f) {
int mx=-inf;
while (bl[x]!=bl[f]) {
mx=max(mx,query(1,pos[bl[x]],pos[x]));
x=fa[bl[x]][0];
}
if (pos[f]+1<=pos[x]) mx=max(mx,query(1,pos[f]+1,pos[x]));
return mx;
}
void solverever(int x,int f) {
while (bl[x]!=bl[f]) {
rever(1,pos[bl[x]],pos[x]);
x=fa[bl[x]][0];
}
if (pos[f]+1<=pos[x]) rever(1,pos[f]+1,pos[x]);
}
int main() {
free("aaa");
int T=getint();
bin[0]=1;for (int i=1;i<15;i++) bin[i]=bin[i-1]<<1;
while (T--) {
P=0,cnt=1;//便于将边权转为点权
memset(head,0,sizeof(head));
memset(deep,0,sizeof(deep));
memset(fa,0,sizeof(fa));
n=getint();
for (int i=1;i<n;i++) {
int u=getint(),v=getint(),w=getint();
insert(u,v,w);
}
build(1,1,n);
dfs1(1);
dfs2(1,1);
char ch[10];
while (scanf("%s",ch+1)) {
if (ch[1]=='D') break;
int x=getint(),y=getint();
if (ch[1]=='Q') {
int f=lca(x,y);
printf("%d\n",max(solvequery(x,f),solvequery(y,f)));
}
if (ch[1]=='C') change(1,to[x],y);
if (ch[1]=='N') {
int f=lca(x,y);
solverever(x,f);solverever(y,f);
}
}
}
fclose(stdin);fclose(stdout);
return 0;
}
【poj3237】 Tree的更多相关文章
- 【POJ3237】Tree 树链剖分+线段树
[POJ3237]Tree Description You are given a tree with N nodes. The tree's nodes are numbered 1 through ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- 【POJ3237】Tree(树链剖分)
题意:在一棵N个节点,有边权的树上维护以下操作: 1:单边修改,将第X条边的边权修改成Y 2:区间取反,将点X与Y在树上路径中的所有边边权取反 3:区间询问最大值,询问X到Y树上路径中边权最大值 n& ...
- 【BZOJ】【2631】Tree
LCT 又一道名字叫做Tree的题目…… 看到删边加边什么的……又是动态树问题……果断再次搬出LCT. 这题比起上道[3282]tree的难点在于需要像线段树维护区间那样,进行树上路径的权值修改&am ...
- 【Luogu1501】Tree(Link-Cut Tree)
[Luogu1501]Tree(Link-Cut Tree) 题面 洛谷 题解 \(LCT\)版子题 看到了顺手敲一下而已 注意一下,别乘爆了 #include<iostream> #in ...
- 【BZOJ3282】Tree (Link-Cut Tree)
[BZOJ3282]Tree (Link-Cut Tree) 题面 BZOJ权限题呀,良心luogu上有 题解 Link-Cut Tree班子提 最近因为NOIP考炸了 学科也炸了 时间显然没有 以后 ...
- 【AtCoder3611】Tree MST(点分治,最小生成树)
[AtCoder3611]Tree MST(点分治,最小生成树) 题面 AtCoder 洛谷 给定一棵\(n\)个节点的树,现有有一张完全图,两点\(x,y\)之间的边长为\(w[x]+w[y]+di ...
- 【HDU5909】Tree Cutting(FWT)
[HDU5909]Tree Cutting(FWT) 题面 vjudge 题目大意: 给你一棵\(n\)个节点的树,每个节点都有一个小于\(m\)的权值 定义一棵子树的权值为所有节点的异或和,问权值为 ...
- 【BZOJ2654】Tree(凸优化,最小生成树)
[BZOJ2654]Tree(凸优化,最小生成树) 题面 BZOJ 洛谷 题解 这道题目是之前\(Apio\)的时候写的,忽然发现自己忘记发博客了... 这个万一就是一个凸优化, 给所有白边二分一个额 ...
随机推荐
- JSTL中的TLD配置和使用。
一,JSTL介绍: JSTL标签库,是日常开发经常使用的,也是众多标签中性能最好的.把常用的内容,放在这里备份一份,随用随查.尽量做到不用查,就可以随手就可以写出来.这算是Java程序员的基本功吧,一 ...
- Parallel.Invoke并行你的代码
Parallel.Invoke并行你的代码 使用Parallel.Invoke并行你的代码 优势和劣势 使用Parallel.Invoke的优势就是使用它执行很多的方法很简单,而不用担心任务或者线程的 ...
- Linux Linux程序练习十六(进程间的通信信号版)
/* * 题目: * 编写程序,要去实现如下功能: 父进程创建子进程1和子进程2.子进程1向子进程2发送可靠信号,并传送额外数据为子进程1的pid*2; 子进程2接受可靠信号的值,并发送给父进程,父进 ...
- 树莓派Odroid等卡片式电脑上搭建NAS教程系列5-Samba服务器安装
本文章首发于浩瀚先森博客,地址: http://www.guohao1206.com/2016/08/23/967.html samba时一款为了实现linux系统中的文件能在windows系统中正常 ...
- 套用GGTalk做项目的经验总结——GGTalk源码详解系列(一)
坦白讲,我们公司其实没啥技术实力,之所以还能不断接到各种项目,全凭我们老板神通广大!要知道他每次的饭局上可都是些什么人物! 但是项目接下一大把,就凭咱哥儿几个的水平,想要独立自主.保质保量保期地一个个 ...
- ASP.NET 系列:单元测试之Log4Net
使用Log组件时,我们通常自定义ILogger接口,使用Log4Net等组件进行适配来定义不同的实现类.使用Log4Net日志组件时,为了即方便单元测试又能使用配置文件,我们通过Log4Net的ILo ...
- get_post
各种http的请求协议: http://ymiter.iteye.com/blog/1922464 HTTP请求报文和HTTP响应报文 http://www.cnblogs.com/biyeymyhj ...
- Android开发环境部署
引言 在windows系统中安装Android的开发环境,将分为五个步骤来完成: 第一步:安装JDK 第二步:配置Windows上JDK的变量环境 第三步: 下载安装Eclipse 第四步:下载安 ...
- codevs 4543 treap 模板
type rec=record lc,rc,v,rnd,size,w,fa:longint; end; var n,root,tot,ans,opt,x,i,po:longint; tr:array[ ...
- 离散系统频响特性函数freqz()
MATLAB提供了专门用于求离散系统频响特性的函数freqz(),调用freqz()的格式有以下两种: l [H,w]=freqz(B,A,N) B和A分别为离散系统的系统函数分子.分母 ...