HDU 3966 dfs序+LCA+树状数组
题目意思很明白:
给你一棵有n个节点的树,对树有下列操作:
I c1 c2 k 意思是把从c1节点到c2节点路径上的点权值加上k
D c1 c2 k 意思是把从c1节点到c2节点路径上的点权值减去k
Q a 查询节点a的权值
数据大小 节点个数 n[1,50000], 操作次数 op[0,30000];
不会树链剖分 故只有想其他的方法。
这道题有点类似今年上海网络赛的1003 ,不过那题我没做;
算法思路:
以节点1 为根,求出节点i 的 dfs序列 tim[i][2];
其中tim[i][0]存的是进入节点i的时间 ,tim[i][1]存的是离开节点i的时间
看操作: I a b k, 节点a到b的路径上所有点+k;最朴素的算法首先找到他们的最近公共祖先(LCA)(我用RMQ)写的;然后在路径上的每一个节点都+k;
假设树根是1
从a到树根的每一个节点x都满足tim[x][0]<=tim[a][0]<=tim[x][1];如此 如果引入一个数列nt,如果nt(tim[a][0])+=k,那么 nt数列从tim[x][0]到tim[x][1]项的和就加了k,这就相当于把从a到根节点的每一个节点的权值加上了k;
如果节点x不在a到根的路径上呢?那么只有可能是tim[x][0]>tim[a][0] or tim[x][1]<tim[a][0] 故上面的这种做法对其他的点没有影响
根据这种思路 ,那解法就相对简单了:
加上差分数列的思想
a b的LCA是t,把 a b节点都加上k,然后把t的父节点-2;当然 t节点是加了两遍的 所以需要减去一遍 也就是把t节点-1,父节点当然也要+1了
如果有了dfs序,就可以很清晰的看出来 如果一个节点x在这条路径上 那么tim[x][0]<=one of (tim[a][0],tim[b][0])<=tim[x][1];
附上代码渣渣:
// hdu 3966
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <string>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<stdlib.h>
#include <vector>
using namespace std; #define ll __int64
#define CL(a,b) memset(a,b,sizeof(a))
#define MAX_NODE 50010 int n,m,q; int log_2(int x)
{
return (int)(log((double)x)/log(2.0));
} int tim[MAX_NODE][],ti;
int rmq[MAX_NODE*][],cq,fv[MAX_NODE];
int pre[MAX_NODE];
int value[]; typedef struct myedge
{
int v,next;
}E; E edge[];
int head[],ce; void inithead()
{
CL(head,-);
ce=;
}
void addedge(int s,int e)
{
edge[ce].v=e;edge[ce].next=head[s];head[s]=ce++;
edge[ce].v=s;edge[ce].next=head[e];head[e]=ce++;
} void initrmq()
{
int i,j;
for(j=;(<<j)<=cq;j++)
{
for(i=;i+(<<j)-<=cq;i++)
{
rmq[i][j]=min(rmq[i][j-],rmq[i+(<<(j-))][j-]);
}
}
}
int quermq(int s,int e)
{
int i=log_2(e-s+);
return min(rmq[s][i],rmq[e-(<<i)+][i]);
} ll nt[]; int lowbit(int i)
{
return i&(-i);
} void modify(int i,ll v)
{
if(i==)return ;
for(i;i<=n;i+=lowbit(i))
{
nt[i]+=v;
}
} ll sum(int i)
{
ll rem=;
for(i;i>;i-=lowbit(i))
rem+=nt[i];
return rem;
} int dfs(int i,int pr)
{
ti++;
tim[i][]=ti;
// cout<<i<<" tim "<<ti<<endl;
rmq[++cq][]=tim[i][];
fv[i]=cq;
pre[ti]=pr;
int p=head[i];
while(p!=-)
{
int v=edge[p].v;
if(tim[v][]==)
{
dfs(v,tim[i][]);
rmq[++cq][]=tim[i][];
}
p=edge[p].next;
}
tim[i][]=ti;
return ;
} void inc(int s,int e,int k)
{
int rs=fv[s];
int re=fv[e];
int rt=quermq(min(rs,re),max(rs,re));
re=tim[e][];
rs=tim[s][];
// cout<<rs<<' '<<re<<' '<<rt<<' '<<pre[rt]<<endl;
if(s==e)
{
value[s]+=k;
return ;
}
modify(rs,k);
modify(re,k);
modify(rt,-k);
modify(pre[rt],-k);
} void dec(int s,int e,int k)
{
k=-k;
int rs=fv[s];
int re=fv[e];
int rt=quermq(min(rs,re),max(rs,re));
re=tim[e][];
rs=tim[s][];
if(s==e)
{
value[s]+=k;
return ;
}
modify(rs,k);
modify(re,k);
modify(rt,-k);
modify(pre[rt],-k);
} ll que(int k)
{
int rl=tim[k][];
int rr=tim[k][];
// cout<<rl<<' '<<rr<<endl;
return (ll)value[k]+sum(rr)-sum(rl-);
} char op[]; int main()
{
while(scanf("%d %d %d",&n,&m,&q)!=EOF)
{
CL(nt,);
CL(rmq,);cq=;
CL(fv,);
CL(pre,);
CL(tim,);ti=;
inithead();
int i,j,k;
int a,b,c;
for(i=;i<=n;i++)
{
scanf("%d",value+i);
}
for(i=;i<n;i++)
{
scanf("%d %d",&a,&b);
addedge(a,b);
}
dfs(,);
/*
for(i=1;i<=cq;i++)
{
printf("%d ",rmq[i][0]);
}cout<<endl;
*/
initrmq();
for(i=;i<q;i++)
{
scanf("%s",op);
if(op[]=='I')
{
scanf("%d %d %d",&a,&b,&c);
inc(a,b,c);
}
else if(op[]=='D')
{
scanf("%d %d %d",&a,&b,&c);
dec(a,b,c);
}
else if(op[]=='Q')
{
scanf("%d",&a);
printf("%I64d\n",que(a));
}
} } return ;
}
HDU 3966 dfs序+LCA+树状数组的更多相关文章
- BZOJ 4999: This Problem Is Too Simple! DFS序+LCA+树状数组+离线
Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) , ...
- HDU 6203 ping ping ping(dfs序+LCA+树状数组)
http://acm.hdu.edu.cn/showproblem.php?pid=6203 题意: n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V 无法连 ...
- POJ 2763 Housewife Wind(DFS序+LCA+树状数组)
Housewife Wind Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 11419 Accepted: 3140 D ...
- BZOJ 2819: Nim dfs序维护树状数组,倍增
1.随机选两个堆v,u,询问若在v到u间的路径上的石子堆中玩Nim游戏,是否有必胜策略,如果有,vfleaking将会考虑将这些石子堆作为初始局面之一,用来坑玩家.2.把堆v中的石子数变为k. 分析: ...
- 【BZOJ1103】大都市meg(DFS序,树状数组)
题意:有一颗树,1号点为根,保证编号小的点深度较小,初始状态每条边都没有被标记,要求实现两个操作在线: A:将连接x,y的边标记 W:查询从1到x的路径上有多少条边未被标记 n<=2*10^5 ...
- 2018.06.30 BZOJ4765: 普通计算姬(dfs序+分块+树状数组)
4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MB Description "奋战三星期,造台计算机".小G响应号召,花了三小时 ...
- BZOJ 1103: [POI2007]大都市meg(dfs序,树状数组)
本来还想链剖的,结果才发现能直接树状数组的= = 记录遍历到达点与退出点的时间,然后一开始每个到达时间+1,退出时间-1,置为公路就-1,+1,询问直接点1到该点到达时间求和就行了- - CODE: ...
- 【Tyvj2133&BZOJ1146】网络管理Network(树套树,DFS序,树状数组,主席树,树上差分)
题意:有一棵N个点的树,每个点有一个点权a[i],要求在线实现以下操作: 1:将X号点的点权修改为Y 2:查询X到Y的路径上第K大的点权 n,q<=80000 a[i]<=10^8 思路: ...
- 【POJ3321】Apple Tree(DFS序,树状数组)
题意:给一棵n个节点的树,每个节点开始有一个苹果,m次操作 1.将某个结点的苹果数异或 1 2.查询一棵子树内的苹果数 n,m<=100000 思路:最近一段时间在思考树上统计问题的算法 发 ...
随机推荐
- window.open窗口居中和窗口最大化
1.window.open()参数 window.open(pageURL,name,parameters) 其中: pageURL为子窗口路径 name为子窗口句柄 parameters为窗口参数( ...
- php字符串处理之全角半角转换
半角全角的处理是字符串处理的常见问题,本文尝试为大家提供一个思路. 一.概念 全角字符unicode编码从65281~65374 (十六进制 0xFF01 ~ 0xFF5E)半角字符unicode编码 ...
- WEB开发中常用的正则表达式
在计算机科学中,正则表达式用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串.在WEB开发中,正则表达式通常用来检测.查找替换某些符合规则的字符串,如检测用户输入E-mai格式是否正确,采集符 ...
- 一个oracle存储过程
打开plsql,在packages文件夹里新建存储过程 在sql窗口中运行如下语句 create or replace package SY_USER_PKG1 is TYPE MYCURSOR IS ...
- JQuery的插件
最近需要修改ftl文件,使用一般的freemarker插件不能有效处理里边的部分JQuery内容,所以特地下载了一个Spket插件, 地址为 http://www.agpad.com/update 再 ...
- FJ省队集训DAY4 T3
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #inclu ...
- POJ1061青蛙的约会(扩展欧几里德算法)
青蛙的约会 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 102239 Accepted: 19781 Descript ...
- linux考试基础知识测验
Linux系统管理基础测试(100分钟) 姓名: 座位号: 一.单项选择题:(每小题0.5分,共计30分) 1. cron 后台常驻程序 (daemon) 用于:D A. 负责文件在网络中的共 ...
- socket用法以及tomcat静态动态页面的加载
一.套接字的使用: 分为以下几步: 1.创建ServerSocket 2.接收客户端的连接 3.读取本地的test.html文件 4.构建数据输出通道 5.发送数据 6.关闭资源 代码参考: pack ...
- 【css3+JavaScript】:一个优雅的对话框
实现效果: 演示地址:http://codepen.io/anon/pen/BNjYrR ======2015/5/11====== 优化滚动条(scroll):默认的滚动条太丑,忍不住优化下 ::- ...