【bzoj1036】 ZJOI2008—树的统计Count
http://www.lydsy.com/JudgeOnline/problem.php?id=1036 (题目链接)
题意
动态维护树上两点间最大权值和权值和。
Solution
裸树链剖分。
这一篇题解并不是本博客的重点。我在找本题的数据生成器的时候发现了一篇神奇的博客。关于如何制造出一棵树的数据,随机构造prufer。
UPD:当年的自己真是脑残,竟然不会构造树的数据→_→
data
#include<cstdio>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<algorithm>
using namespace std;
int a[30000+20];
struct nod
{
int id,d;
}d[30000+20];
bool cmpid(nod x,nod y)//按编号排序
{
return x.id<y.id;
}
bool cmp(nod x,nod y)//按度数排序
{
if(x.d!=y.d)return x.d<y.d;
else return x.id<y.id;
}
int main()
{
freopen("1.in","w",stdout);
srand(time(NULL));
int n=rand()%10+1;
cout<<n<<endl;
for(int i=1;i<=n;i++)
{
d[i].d=1;
d[i].id=i;
}
for(int i=1;i<=n-2;i++)a[i]=rand()%n+1;//生成purfer编码
for(int i=1;i<=n-2;i++)d[a[i]].d++;//累加度数
for(int i=1;i<=n-2;i++)
{
sort(d+1,d+n+1,cmp);
int j;
for(j=1;j<=n;j++)if(d[j].d)break;
printf("%d %d\n",d[j].id,a[i]);
d[j].d--;
sort(d+1,d+n+1,cmpid);
d[a[i]].d--;
} //模拟上述过程,找度数为1且编号最小的和purfer编码中当前位
sort(d+1,d+n+1,cmp);
printf("%d %d\n",d[n-1].id,d[n].id);//最后两个点之间连边
for(int i=1;i<=n;i++)
{
printf("%d ",(rand()%20)-10);
}
int m=rand()%20+1;
cout<<endl;
cout<<m<<endl;
for(int i=1;i<=m;i++)
{
int s=rand()%3+1;
if(s==1)printf("QMAX ");
if(s==2)printf("QSUM ");
if(s==3)printf("CHANGE ");
int a=rand()%n+1;
int b=rand()%a+1;
while(a==b)
{
a=rand()%n+1;
b=rand()%a+1;
}
cout<<a<<" "<<b<<endl;
}
return 0;
}
代码
// bzoj1036
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#define inf 2147483640
#define LL long long
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
inline LL getint() {
LL 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=30010;
struct edge {int to,next;}e[maxn<<2];
struct tree {int s,mx,l,r;}tr[maxn<<2];
int a[maxn],pos[maxn],head[maxn],bl[maxn],size[maxn],deep[maxn],fa[maxn][20],bin[20];
int cnt,n,q; void insert(int u,int v) {
e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;
}
void build(int k,int s,int t) {
tr[k].l=s,tr[k].r=t,tr[k].s=0,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 update(int k,int s,int val) {
int l=tr[k].l,r=tr[k].r;
if (l==r && l==s) {tr[k].s=tr[k].mx=val;return;}
int mid=(l+r)>>1;
if (s<=mid) update(k<<1,s,val);
else update(k<<1|1,s,val);
tr[k].s=tr[k<<1].s+tr[k<<1|1].s;
tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);
}
int querymx(int k,int s,int t) {
int l=tr[k].l,r=tr[k].r;
if (l==s && r==t) return tr[k].mx;
int mid=(l+r)>>1;
if (t<=mid) return querymx(k<<1,s,t);
else if (s>mid) return querymx(k<<1|1,s,t);
else return max(querymx(k<<1,s,mid),querymx(k<<1|1,mid+1,t));
}
int querys(int k,int s,int t) {
int l=tr[k].l,r=tr[k].r;
if (l==s && r==t) return tr[k].s;
int mid=(l+r)>>1;
if (t<=mid) return querys(k<<1,s,t);
else if (s>mid) return querys(k<<1|1,s,t);
else return querys(k<<1,s,mid)+querys(k<<1|1,mid+1,t);
}
void dfs1(int x) {
size[x]=1;
for (int i=1;i<20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
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) {
bl[x]=chain;
pos[x]=++cnt;
update(1,pos[x],a[x]);
int k=0;
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0])
if (size[k]<size[e[i].to]) k=e[i].to;
if (k!=0) 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;bin[i]<=t;i++) if (bin[i]&t) x=fa[x][i];
for (int i=19;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return x==y?x:fa[x][0];
}
int solvemx(int x,int f) {
if (x==f) return a[x];
int mx=-inf;
while (bl[x]!=bl[f]) {
mx=max(mx,querymx(1,pos[bl[x]],pos[x]));
x=fa[bl[x]][0];
}
if (pos[f]<=pos[x]) mx=max(mx,querymx(1,pos[f],pos[x]));
return mx;
}
int solves(int x,int f) {
if (x==f) return a[x];
int s=0;
while (bl[x]!=bl[f]) {
s+=querys(1,pos[bl[x]],pos[x]);
x=fa[bl[x]][0];
}
if (pos[f]<=pos[x]) s+=querys(1,pos[f],pos[x]);
return s;
}
int main() {
bin[0]=1;for (int i=1;i<20;i++) bin[i]=bin[i-1]<<1;
scanf("%d",&n);
for (int i=1;i<n;i++) {
int u,v;
scanf("%d%d",&u,&v);
insert(u,v);
}
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
cnt=0;
build(1,1,n);
dfs1(1);dfs2(1,1);
scanf("%d",&q);
while (q--) {
char ch[10];int x,y;
scanf("%s%d%d",ch,&x,&y);
if (ch[0]=='C') update(1,pos[x],y),a[x]=y;
else if (ch[1]=='M') {
int f=lca(x,y);
printf("%d\n",max(solvemx(x,f),solvemx(y,f)));
}
else {
int f=lca(x,y);
printf("%d\n",solves(x,f)+solves(y,f)-a[f]);
}
}
return 0;
}
【bzoj1036】 ZJOI2008—树的统计Count的更多相关文章
- [BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分
树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设( ...
- bzoj1036 [ZJOI2008]树的统计Count
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MB Submit: 12646 Solved: 5085 [Subm ...
- bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题
[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...
- bzoj千题计划124:bzoj1036: [ZJOI2008]树的统计Count
http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分板子题 #include<cstdio> #include<iost ...
- BZOJ1036 [ZJOI2008]树的统计Count 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1036 题意概括 一个树,每个节点有一个权值.3种操作. 1:修改某一个节点的权值. 2:询问某两个 ...
- 【lct】bzoj1036 [ZJOI2008]树的统计Count
题意:给你一棵树,点带权,支持三种操作:单点修改:询问链上和:询问链上max. 这里的Query操作用了与上一题不太一样的做法(上一题用那种做法,因为在边带权的情况下换根太困难啦): 先ChangeR ...
- BZOJ1036[ZJOI2008]树的统计Count 题解
题目大意: 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.有一些操作:1.把结点u的权值改为t:2.询问从点u到点v的路径上的节点的最大权值 3.询问从点u到点v的路径上的节点的权值和 ...
- bzoj1036 zjoi2008 树的统计 count
填坑= =第一道裸树剖 #include<cstdio> #include<algorithm> #include<cstring> #include<cst ...
- [BZOJ1036] [ZJOI2008] 树的统计Count (LCT)
Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. Q ...
- bzoj1036 [ZJOI2008]树的统计Count(树链剖分)
Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. Q ...
随机推荐
- Android系列之Fragment(三)----Fragment和Activity之间的通信(含接口回调)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...
- Java Executor并发框架(三)ThreadPoolExecutor 队列缓存策略
前面两篇讲解了线程池中线程创建后的运行情况,其中有一系列的策略来保证线程正常运行.但是我们知道线程池是可以设置容量的,而且这容量的设置也是至关重要的,如果容量设置的太小,那么将会影响系统的运行效率,如 ...
- 文件泄露&php代码审计
这道题,还是很不错的.卡在了token绕过那里,不得已看了别人的writeUp,才做出来,惭愧! 但还是想写写WriteUp做一下记录! 首先是打开题目,习惯性查看源码,发现了点蛛丝马迹 知道了,管理 ...
- 【转】【C++】ShellExecute, WinExec, CreateProcess 三者的区别
ShellExecute ShellExecute的功能是运行一个外部程序(或者是打开一个已注册的文件.打开一个目录.打印一个文件等等),并对外部程序有一定的控制. 有几个API函数都可以实现这些功能 ...
- C语言 文件操作2--文件缓存的理解
//文件缓存机制理解 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> void mai ...
- 公钥(Public Key)与私钥(Private Key)
公钥(Public Key)与私钥(Private Key)是通过一种算法得到的一个密钥对(即一个公钥和一个私钥),公钥是密钥对中公开的部分,私钥则是非公开的部分.公钥通常用于加密会话密钥.验证数字签 ...
- [iOS翻译]《iOS7 by Tutorials》系列:在Xcode 5里使用单元测试(上)
简介: 单元测试是软件开发的一个重要方面.毕竟,单元测试可以帮你找到bug和崩溃原因,而程序崩溃是Apple在审查时拒绝app上架的首要原因. 单元测试不是万能的,但Apple把它作为开发工具包的一部 ...
- WebSocket 服务器4
Java Websocket实例 Websocket 2015-04-11 14:11:54 发布 您的评价: 4.4 收藏 6收藏 介绍 现很多网站为了实现即时通讯,所用 ...
- window8配置IIS,搭建应用程序网站。
这个里面的一定要勾选,不然会有莫名其妙的错误. 在应用程序池中,如果你是64位电脑,需勾选启用32位应用程序为 true
- struct2cell
函数功能:把结构体转换为元胞数组. 语法格式: c = struct2cell(s) 如果s是m*n(m行n列)的二维的结构体数组,每个结构体含有p个域,则转换得到一个p*m*n的元胞数组c. 如果s ...