[kuangbin带你飞]专题七 线段树
ID
|
Origin
|
Title
|
||
---|---|---|---|---|
228 / 440 | Problem A | HDU 1166 | 敌兵布阵 | |
207 / 438 | Problem B | HDU 1754 | I Hate It | |
181 / 727 | Problem C | POJ 3468 | A Simple Problem with Integers | |
105 / 410 | Problem D | POJ 2528 | Mayor's posters | |
138 / 230 | Problem E | HDU 1698 | Just a Hook | |
105 / 305 | Problem F | ZOJ 1610 | Count the Colors | |
120 / 176 | Problem G | POJ 3264 | Balanced Lineup | |
93 / 406 | Problem H | HDU 4027 | Can you answer these queries? | |
73 / 183 | Problem I | HDU 1540 | Tunnel Warfare | |
61 / 164 | Problem J | HDU 3974 | Assign the task | |
27 / 105 | Problem K | HDU 4578 | Transformation | |
32 / 103 | Problem L | HDU 4614 | Vases and Flowers | |
29 / 139 | Problem M | HDU 4553 | 约会安排 | |
35 / 52 | Problem N | POJ 1177 | Picture | |
37 / 67 | Problem O | HDU 1255 | 覆盖的面积 | |
40 / 88 | Problem P | HDU 1542 | Atlantis | |
7 / 15 | Problem Q | HDU 3642 | Get The Treasury |
228 / 440 Problem A HDU 1166 敌兵布阵
hint.解题报告见之前博客
207 / 438 Problem B HDU 1754 I Hate It
d.给出N个学生的成绩,现在有2种操作,
操作1:询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
操作2:把ID为A的学生的成绩更改为B。
对于每个询问,输出最高成绩。
s.线段树单点更新,区间查询。
#include<iostream>
#include<stdio.h>
using namespace std; #define MAXN 200005
int ans; int grade[MAXN]; struct node{
int left,right;//,sum;
int ma;//区间最大值
int mid(){
return (left+right)>>;
}
}tree[MAXN*];//注意范围,4倍空间 void btree(int left,int right,int rt){//建树
tree[rt].left=left;
tree[rt].right=right;
if(left==right){
//scanf("%d",&tree[rt].sum);
tree[rt].ma=grade[left];
return;
}
int mid=tree[rt].mid();
btree(left,mid,rt<<);
btree(mid+,right,rt<<|);
//tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;//区间里的点数=左区间+右区间
tree[rt].ma=tree[rt<<].ma>tree[rt<<|].ma?tree[rt<<].ma:tree[rt<<|].ma;
} void query(int left,int right,int rt,int L,int R){//询问求最大值
if(L<=left&&right<=R){
//ans+=tree[rt].sum;
if(tree[rt].ma>ans){
ans=tree[rt].ma;
}
return;
}
int mid=tree[rt].mid();
if(R<=mid)query(left,mid,rt<<,L,R);//区间在左子树
else if(L>mid)query(mid+,right,rt<<|,L,R);//区间在右子树
else{
query(left,mid,rt<<,L,R);
query(mid+,right,rt<<|,L,R);
}
} void update(int left,int right,int rt,int pos,int add){//单点更新函数
if(left==right){
//tree[rt].sum+=add;
tree[rt].ma=add;
return;
}
int mid=tree[rt].mid();
if(pos<=mid)update(left,mid,rt<<,pos,add);//点在左子树
else update(mid+,right,rt<<|,pos,add);//点在右子树
//tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;//区间和更新
tree[rt].ma=tree[rt<<].ma>tree[rt<<|].ma?tree[rt<<].ma:tree[rt<<|].ma;//区间最大值更新
} int main(){ int N,M;
char str[];
int A,B; while(~scanf("%d%d",&N,&M)){ for(int i=;i<=N;++i){
scanf("%d",&grade[i]);
} btree(,N,); for(int i=;i<M;++i){
scanf("%1s",str);
scanf("%d%d",&A,&B);
if(str[]=='Q'){
ans=;
query(,N,,A,B);
printf("%d\n",ans);
}
else{
update(,N,,A,B);
}
} } return ;
}
181 / 727 Problem C POJ 3468 A Simple Problem with Integers
hint.解题报告见之前博客
105 / 410 Problem D POJ 2528 Mayor's posters
d.n张海报,高度相同,给出要贴在墙上的左右端点,后面贴的覆盖前面的,求最后能看到的海报数。
s.宽度范围很大,离散化
c.从前向后贴
/*
线段树
区间更新
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std; #define L(root) ((root)<<1)
#define R(root) (((root)<<1)|1) const int MAXN=;//
int numbers[MAXN];//初始值 int myHash[];
bool vis[MAXN];//这种颜色存在标志 struct node{
int left,right;//
int color;
int flag;//-1不向下更新,1向下更新,即单色时
int mid(){
return left+((right-left)>>);
}
}tree[MAXN**];//4倍空间 void pushUp(int root){
} void pushDown(int root){ if(tree[root].flag==){//需要向下更新
tree[L(root)].flag=;
tree[R(root)].flag=;
tree[L(root)].color=tree[root].color;
tree[R(root)].color=tree[root].color;
tree[root].flag=-;
}
} void build(int root,int left,int right){
tree[root].left=left;
tree[root].right=right; tree[root].flag=-;
if(left==right){
return;
}
int mid=tree[root].mid();
build(L(root),left,mid);
build(R(root),mid+,right);
} int query(int root,int left,int right){ if(tree[root].flag==){//当前区间为单色的
if(!vis[tree[root].color]){//第一次出现这种颜色
vis[tree[root].color]=true;
return ;
}
return ;
} int mid=tree[root].mid();
if(right<=mid){
return query(L(root),left,right);
}
else if(left>mid){
return query(R(root),left,right);
}
else{
return query(L(root),left,mid)+query(R(root),mid+,right);
}
} void update(int root,int left,int right,int add){
if(tree[root].flag==&&tree[root].color==add){
return;//小剪枝,当前区间单色且与要更改的区间颜色相同则返回不用深入
} if(tree[root].left==left&&tree[root].right==right){
tree[root].color=add;
tree[root].flag=;
return;
}
pushDown(root);
int mid=tree[root].mid();
if(right<=mid){
update(L(root),left,right,add);
}
else if(left>mid){
update(R(root),left,right,add);
}
else{
update(L(root),left,mid,add);
update(R(root),mid+,right,add);
}
} int main(){ int c;
int n;
int post[MAXN][];//每个区间
int p[MAXN*];//所有的点
int cnt;//所有点的个数
int p2[MAXN*];//去除重复
int cnt2; int i; scanf("%d",&c);
while(c--){
scanf("%d",&n);
cnt=;
for(i=;i<n;++i){
scanf("%d%d",&post[i][],&post[i][]);
p[cnt++]=post[i][];//保存所有端点
p[cnt++]=post[i][];
}
sort(p,p+cnt);//排序 p2[]=p[];
cnt2=;
for(i=;i<cnt;++i){//去重
if(p[i]!=p[i-]){
p2[cnt2++]=p[i];
}
} for(i=;i<cnt2;++i){//所有点hash映射到0~cnt2-1
myHash[p2[i]]=i;
} build(,,cnt2-);//0~cnt2-1
for(i=;i<n;++i){//n种颜色从头开始涂
update(,myHash[post[i][]],myHash[post[i][]],i);
} memset(vis,false,sizeof(vis));
printf("%d\n",query(,,cnt2-));//0~cnt2-1
} return ;
}
c2.从后向前看
/*
HDU 2528 Mayor's posters
本题大意:给定一些海报,可能相互重叠,告诉你每个海报
的宽度(高度都一样的)和先后叠放顺序,问没有被完全盖住的有多少张?
海报最多10000张,但是墙有10000000块瓷砖长,海报不会落在瓷砖中间。
如果直接建树,就算不TLE,也会MLE。即单位区间长度太多。
其实10000张海报,有20000个点,最多有19999个区间。对各个区间编号,就是离散化。然后建数。
其实浮点数也是一样离散化的。 writer:kuangbin
*/
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int MAXN=;
struct Cpost
{
int l,r;
} posters[MAXN];
int x[MAXN*];
int hash[];
struct Node
{
int l,r;
bool bCovered;//标记是否被完全覆盖
} segTree[MAXN*]; //这里必须开到线段数的四倍,??
void Build(int i,int l,int r)//建立线段树
{
segTree[i].l=l;
segTree[i].r=r;
segTree[i].bCovered=false;
if(l==r)return;
int mid=(l+r)>>;
Build(i<<,l,mid);
Build(i<<|,mid+,r);
}
bool Post(int i,int l,int r)//贴上一个好报,同时判断是否被完全覆盖
{
if(segTree[i].bCovered) return false;
if(segTree[i].l==l&&segTree[i].r==r)
{
segTree[i].bCovered=true;
return true;
}
bool bResult;
int mid=(segTree[i].l+segTree[i].r)>>;
if(r<=mid) bResult=Post(i<<,l,r);
else if(l>mid)
bResult=Post(i<<|,l,r);
else
{
bool b1=Post(i<<,l,mid);
bool b2=Post(i<<|,mid+,r);
bResult=b1||b2;//不能直接或上去,因为如果前面的真,后面的会不做的
}
//这个很重要,要反馈回原结点,如果左右儿子都被完全覆盖了,自然也完全覆盖了
if(segTree[i<<].bCovered && segTree[i<<|].bCovered)
segTree[i].bCovered=true;
return bResult;
}
int main()
{
int T;
int i,j,k;
int n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int nCount=;
for(i=; i<n; i++)
{
scanf("%d%d",&posters[i].l,&posters[i].r);
x[nCount++]=posters[i].l;
x[nCount++]=posters[i].r;
}
sort(x,x+nCount);//先排序
nCount=unique(x,x+nCount)-x;//合并掉相同的项
for(i=; i<nCount; i++)
hash[x[i]]=i;
Build(,,nCount-);
int res=;
for(i=n-; i>=; i--) //要从上面开始看。
if(Post(,hash[posters[i].l],hash[posters[i].r]))
res++;
printf("%d\n",res);
}
return ;
}
138 / 230 Problem E HDU 1698 Just a Hook
d.刚开始区间内元素全是1,每次操作可以把一个区间里的值全都变为1或2或3,求经过一些操作后,整个区间的元素的和
s.区间更新,区间查询。
#include<iostream>
#include<stdio.h>
using namespace std; #define L(root) ((root) << 1)
#define R(root) (((root) << 1) + 1) const int MAXN = ;
//int numbers[MAXN]; struct st
{
// 区间范围
int left, right;
// 更新值、区间总和
long long delta, sum;
} st[MAXN * ]; // 建树代码基本不变
void build(int root, int l, int r)
{
st[root].left = l, st[root].right = r, st[root].delta = ;
if (l == r)
{
//st[root].sum = numbers[l];
st[root].sum=;
return;
} int m = l + ((r - l) >> );
build(L(root), l, m);
build(R(root), m + , r);
st[root].sum = st[L(root)].sum + st[R(root)].sum;
} long long query(int root, int l, int r)
{
// 如查询区间恰等于节点区间,直接返回该区间总和即可
if (st[root].left == l && st[root].right == r)
{
return st[root].sum;
} // 否则需将当前区间的“缓冲”值更新下去并修正各节点区间的总和
if (st[root].delta)
{
st[L(root)].delta = st[root].delta;
st[R(root)].delta = st[root].delta;
st[L(root)].sum = st[root].delta * (st[L(root)].right - st[L(root)].left + );
st[R(root)].sum = st[root].delta * (st[R(root)].right - st[R(root)].left + );
st[root].delta = ;
} int m = st[root].left + ((st[root].right - st[root].left) >> );
if (r <= m)
{
return query(L(root), l, r);
}
else if (l > m)
{
return query(R(root), l, r);
}
else
{
return query(L(root), l, m) + query(R(root), m + , r);
}
} void update(int root, int l, int r, long long v)
{
// 如变更区间恰等于节点区间,只修正当前节点区间即可
if (st[root].left == l && st[root].right == r)
{
st[root].delta = v;
st[root].sum = v * (r - l + );
return;
} // 否则需向下修正相关节点区间
if (st[root].delta)
{
st[L(root)].delta = st[root].delta;
st[R(root)].delta = st[root].delta;
st[L(root)].sum = st[root].delta * (st[L(root)].right - st[L(root)].left + );
st[R(root)].sum = st[root].delta * (st[R(root)].right - st[R(root)].left + );
st[root].delta = ;
} int m = st[root].left + ((st[root].right - st[root].left) >> );
if (r <= m)
{
update(L(root), l, r, v);
}
else if (l > m)
{
update(R(root), l, r, v);
}
else
{
update(L(root), l, m, v);
update(R(root), m + , r, v);
}
// 同时一定要记得修正当前节点区间的总和
st[root].sum = st[L(root)].sum + st[R(root)].sum;
} int main()
{ int T,N,Q;
int X,Y,Z;
__int64 ans;
int C=; scanf("%d",&T); while(T--){ scanf("%d",&N);
build(,,N); scanf("%d",&Q);
for(int i=;i<Q;++i){
scanf("%d%d%d",&X,&Y,&Z);
update(,X,Y,Z);
} ans=query(,,N); printf("Case %d: The total value of the hook is %I64d.\n",++C,ans); } return ;
}
c2.一个map写的代码,思想不错。不过最坏是O(MQ)
#include<stdio.h>
const int n = ;
int map[n][];
int main()
{
int i,M,z,N,sum,v;
scanf("%d",&N);
for(i=; i<=N; i++)
{
sum = ;
int Q,j;
scanf("%d%d",&M,&Q);
for(j=; j<=Q; j++)
scanf("%d%d%d",&map[j][],&map[j][],&map[j][]);
for(j=; j<=M; j++)
{
v = ;
for(int k=Q; k>=; k--)//从末尾开始 即从更新的最后一次算起
if(map[k][]<=j && j<=map[k][])
{
v = map[k][];
break;//覆盖便弹出
}
sum += v;
}
printf("Case %d: The total value of the hook is %d.\n",i,sum);
}
}
105 / 305 Problem F ZOJ 1610 Count the Colors
hint.解题报告见之前博客
120 / 176 Problem G POJ 3264 Balanced Lineup
d.区间最大值最小值的差
/*
POJ 3264 Balanced Lineup
题目意思:给定Q(1<=Q<=200000)个数A1,A2,```,AQ,
多次求任一区间Ai-Aj中最大数和最小数的差
*/
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define MAXN 200005
#define INF 10000000
int nMax,nMin;//记录最大最小值
struct Node
{
int l,r;//区间的左右端点
int nMin,nMax;//区间的最小值和最大值
}segTree[MAXN*];
int a[MAXN];
void Build(int i,int l,int r)//在结点i上建立区间为(l,r)
{
segTree[i].l=l;
segTree[i].r=r;
if(l==r)//叶子结点
{
segTree[i].nMin=segTree[i].nMax=a[l];
return;
}
int mid=(l+r)>>;
Build(i<<,l,mid);
Build(i<<|,mid+,r);
segTree[i].nMin=min(segTree[i<<].nMin,segTree[i<<|].nMin);
segTree[i].nMax=max(segTree[i<<].nMax,segTree[i<<|].nMax);
}
void Query(int i,int l,int r)//查询结点i上l-r的最大值和最小值
{
if(segTree[i].nMax<=nMax&&segTree[i].nMin>=nMin) return;
if(segTree[i].l==l&&segTree[i].r==r)
{
nMax=max(segTree[i].nMax,nMax);
nMin=min(segTree[i].nMin,nMin);
return;
}
int mid=(segTree[i].l+segTree[i].r)>>;
if(r<=mid) Query(i<<,l,r);
else if(l>mid) Query(i<<|,l,r);
else
{
Query(i<<,l,mid);
Query(i<<|,mid+,r);
}
}
int main()
{
int n,q;
int l,r;
int i;
while(scanf("%d%d",&n,&q)!=EOF)
{
for(i=;i<=n;i++)
scanf("%d",&a[i]);
Build(,,n);
for(i=;i<=q;i++)
{
scanf("%d%d",&l,&r);
nMax=-INF;nMin=INF;
Query(,l,r);
printf("%d\n",nMax-nMin);
}
}
return ;
}
93 / 406 Problem H HDU 4027 Can you answer these queries?
题意:给你N个数,有M个操作,操作有两类,
(1)"0 l r",表示将区间[l,r]里的每个数都开根号。
(2)"1 l r",表示查询区间[l,r]里所有数的和。
/*
HDU 4027 Can you answer these queries? */
#include<stdio.h>
#include<iostream>
#include<math.h>
using namespace std;
const int MAXN=;
struct Node
{
int l,r;
long long sum;
}segTree[MAXN*];
void Build(int i,int l,int r)
{
segTree[i].l=l;
segTree[i].r=r;
if(l==r)
{
scanf("%I64d",&segTree[i].sum);
return;
}
int mid=((l+r)>>);
Build(i<<,l,mid);
Build((i<<)|,mid+,r);
segTree[i].sum=segTree[i<<].sum+segTree[(i<<)|].sum;
}
void action(int i,int l,int r)
{
if(segTree[i].l==l && segTree[i].r==r && segTree[i].sum==r-l+) return;
if(segTree[i].l==segTree[i].r)
{
segTree[i].sum=sqrt(segTree[i].sum*1.0);
return;
}
int mid=((segTree[i].l+segTree[i].r)>>);
if(r<=mid) action(i<<,l,r);
else if(l>mid) action((i<<)|,l,r);
else
{
action(i<<,l,mid);
action((i<<)|,mid+,r);
}
segTree[i].sum=segTree[i<<].sum+segTree[(i<<)|].sum;
}
long long SUM(int i,int l,int r)
{
if(l==segTree[i].l && r==segTree[i].r) return segTree[i].sum; int mid=((segTree[i].l+segTree[i].r)/);
long long ans=; if(r<=mid) ans=SUM(i<<,l,r);
else if(l>mid) ans=SUM((i<<)|,l,r);
else
{
ans+=SUM(i<<,l,mid);
ans+=SUM((i<<)|,mid+,r);
}
return ans;
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n;
int T,X,Y;
int iCase=;
int M;
while(scanf("%d",&n)!=EOF)
{
iCase++;
Build(,,n);
scanf("%d",&M);
printf("Case #%d:\n",iCase);
while(M--)
{
scanf("%d%d%d",&T,&X,&Y);
if(X>Y)swap(X,Y);//这个很重要
if(T==) action(,X,Y);
//else printf("%I64d\n",sum(1,X,Y));
else printf("%I64d\n",SUM(,X,Y));
}
printf("\n");
}
return ;
}
73 / 183 Problem I HDU 1540 Tunnel Warfare
/*
HDU 1540 Tunnel Warfare
题义是对于一段线段,D x 表示破坏x点,
R 表示回复最近一次被破坏的点,Q x表示
询问以x点为中心的两头的最长的连续区间。 */ #include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=;
struct Node
{
int l,r;
int ll,rl,ml;
//左端点开始向左连续的最大长度和右端点开始向左最大的连续长度
//以及这个区间最大连续长度
}segTree[MAXN*];
void Build(int i,int l,int r)
{
segTree[i].l=l;
segTree[i].r=r;
segTree[i].ll=segTree[i].rl=segTree[i].ml=r-l+;
if(l==r)return;
int mid=(l+r)>>;
Build(i<<,l,mid);
Build((i<<)|,mid+,r);
}
void update(int i,int t,int val)
{
if(segTree[i].l==segTree[i].r)
{
if(val==)segTree[i].ll=segTree[i].rl=segTree[i].ml=;
else segTree[i].ll=segTree[i].rl=segTree[i].ml=;
return;
}
int mid=(segTree[i].l+segTree[i].r)>>;
if(t<=mid)update(i<<,t,val);
else update((i<<)|,t,val);
segTree[i].ll=segTree[i<<].ll;
segTree[i].rl=segTree[(i<<)|].rl;
segTree[i].ml=max(segTree[i<<].ml,segTree[(i<<)|].ml);
segTree[i].ml=max(segTree[i].ml,segTree[i<<].rl+segTree[(i<<)|].ll);//解还有可能在中间那部分 if(segTree[i<<].ll==segTree[i<<].r-segTree[i<<].l+)segTree[i].ll+=segTree[(i<<)|].ll;
if(segTree[(i<<)|].rl==segTree[(i<<)|].r-segTree[(i<<)|].l+)
segTree[i].rl+=segTree[i<<].rl;
}
int query(int i,int t)
{
if(segTree[i].l==segTree[i].r||segTree[i].ml==||segTree[i].ml==segTree[i].r-segTree[i].l+)
{
return segTree[i].ml;
}
int mid=(segTree[i].l+segTree[i].r)>>;
if(t<=mid)
{
if(t>=segTree[i<<].r-segTree[i<<].rl+)//仔细想想
return query(i<<,t)+query((i<<)|,mid+);
else return query(i<<,t);
}
else
{
if(t<=segTree[(i<<)|].l+segTree[(i<<)|].ll-)
return query((i<<)|,t)+query(i<<,mid);
else return query((i<<)|,t);
}
}
int que[MAXN];
int top;
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n,m;
char str[];
int x;
while(scanf("%d%d",&n,&m)!=EOF)
{
Build(,,n);
top=;
while(m--)
{
scanf("%s",&str);
if(str[]=='D')
{
scanf("%d",&x);
que[top++]=x; update(,x,); }
else if(str[]=='Q')
{
scanf("%d",&x);
printf("%d\n",query(,x));
}
else
{
if(x>)
{
x=que[--top]; update(,x,);
} }
}
}
return ;
}
61 / 164 Problem J HDU 3974 Assign the task
d.N个员工,N-1条有向边,构成一颗树,边v->u表示v是u的直接上属。有两种操作,
C x表示查询x员工当前的任务
T x y表示给x员工安排y任务
新的任务会覆盖前面的任务。
怎么转换成线段树的?从根节点开始进行一次dfs,上下属关系转换成区间包含关系。比较巧妙。
然后就是区间更新,单点查询。
/* ***********************************************
Author :kuangbin
Created Time :2013-11-17 19:50:24
File Name :E:\2013ACM\比赛练习\2013-11-17\C.cpp
************************************************ */ #include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std; const int MAXN = ;
struct Edge
{
int to,next;
}edge[MAXN];
int head[MAXN],tot;
int cnt;
int start[MAXN],_end[MAXN];
void init()
{
cnt = ;
tot = ;
memset(head,-,sizeof(head));
}
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u)
{
++cnt;
start[u] = cnt;
for(int i = head[u];i != -;i = edge[i].next)
{
dfs(edge[i].to);
}
_end[u] = cnt;
}
struct Node
{
int l,r;
int val;
int lazy;
}segTree[MAXN*];
void Update_Same(int r,int v)
{
if(r)
{
segTree[r].val = v;
segTree[r].lazy = ;
}
}
void push_down(int r)
{
if(segTree[r].lazy)
{
Update_Same(r<<,segTree[r].val);
Update_Same((r<<)|,segTree[r].val);
segTree[r].lazy = ;
}
}
void Build(int i,int l,int r)
{
segTree[i].l = l;
segTree[i].r = r;
segTree[i].val = -;
segTree[i].lazy = ;
if(l == r)return;
int mid = (l+r)/;
Build(i<<,l,mid);
Build((i<<)|,mid+,r);
}
void update(int i,int l,int r,int v)
{
if(segTree[i].l == l && segTree[i].r == r)
{
Update_Same(i,v);
return;
}
push_down(i);
int mid = (segTree[i].l + segTree[i].r)/;
if(r <= mid)update(i<<,l,r,v);
else if(l > mid)update((i<<)|,l,r,v);
else
{
update(i<<,l,mid,v);
update((i<<)|,mid+,r,v);
}
}
int query(int i,int u)
{
if(segTree[i].l == u && segTree[i].r == u)
return segTree[i].val;
push_down(i);
int mid = (segTree[i].l + segTree[i].r)/;
if(u <= mid)return query(i<<,u);
else return query((i<<)|,u);
}
bool used[MAXN];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;
int T;
scanf("%d",&T);
int iCase = ;
while(T--)
{
iCase++;
printf("Case #%d:\n",iCase);
int u,v;
memset(used,false,sizeof(used));
init();
scanf("%d",&n);
for(int i = ;i < n;i++)
{
scanf("%d%d",&u,&v);
used[u] = true;
addedge(v,u);
}
for(int i = ;i <= n;i++)
if(!used[i])
{
dfs(i);
break;
}
Build(,,cnt);
char op[];
int m;
scanf("%d",&m);
while(m--)
{
scanf("%s",op);
if(op[] == 'C')
{
scanf("%d",&u);
printf("%d\n",query(,start[u]));
}
else
{
scanf("%d%d",&u,&v);
update(,start[u],_end[u],v);
}
}
}
return ;
}
27 / 105 Problem K HDU 4578 Transformation
很裸的线段树的题目。但是做起来比较麻烦。
我用sum1,sum2,sum3分别代表和、平方和、立方和。
懒惰标记使用三个变量:
lazy1:是加的数
lazy2:是乘的倍数
lazy3:是赋值为一个常数,为0表示没有。
更新操作需要注意很多细节。
/* **********************************************
Author : kuangbin
Created Time: 2013/8/10 13:24:03
File Name : F:\2013ACM练习\比赛练习\2013杭州邀请赛重现\1003.cpp
*********************************************** */ #include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
const int MOD = ;
const int MAXN = ;
struct Node
{
int l,r;
int sum1,sum2,sum3;
int lazy1,lazy2,lazy3;
}segTree[MAXN*];
void build(int i,int l,int r)
{
segTree[i].l = l;
segTree[i].r = r;
segTree[i].sum1 = segTree[i].sum2 = segTree[i].sum3 = ;
segTree[i].lazy1 = segTree[i].lazy3 = ;
segTree[i].lazy2 = ;
int mid = (l+r)/;
if(l == r)return;
build(i<<,l,mid);
build((i<<)|,mid+,r);
}
void push_up(int i)
{
if(segTree[i].l == segTree[i].r)//这个判断以前都没用过啊。。。不用会出错吗?
return;
segTree[i].sum1 = (segTree[i<<].sum1 + segTree[(i<<)|].sum1)%MOD;
segTree[i].sum2 = (segTree[i<<].sum2 + segTree[(i<<)|].sum2)%MOD;
segTree[i].sum3 = (segTree[i<<].sum3 + segTree[(i<<)|].sum3)%MOD; } void push_down(int i)
{
if(segTree[i].l == segTree[i].r) return;//
if(segTree[i].lazy3 != )//为什么先看lazy3呢?想了下,这个置数优先级更高。
{
segTree[i<<].lazy3 = segTree[(i<<)|].lazy3 = segTree[i].lazy3;
segTree[i<<].lazy1 = segTree[(i<<)|].lazy1 = ;
segTree[i<<].lazy2 = segTree[(i<<)|].lazy2 = ;
segTree[i<<].sum1 = (segTree[i<<].r - segTree[i<<].l + )*segTree[i<<].lazy3%MOD;
segTree[i<<].sum2 = (segTree[i<<].r - segTree[i<<].l + )*segTree[i<<].lazy3%MOD*segTree[i<<].lazy3%MOD;
segTree[i<<].sum3 = (segTree[i<<].r - segTree[i<<].l + )*segTree[i<<].lazy3%MOD*segTree[i<<].lazy3%MOD*segTree[i<<].lazy3%MOD;
segTree[(i<<)|].sum1 = (segTree[(i<<)|].r - segTree[(i<<)|].l + )*segTree[(i<<)|].lazy3%MOD;
segTree[(i<<)|].sum2 = (segTree[(i<<)|].r - segTree[(i<<)|].l + )*segTree[(i<<)|].lazy3%MOD*segTree[(i<<)|].lazy3%MOD;
segTree[(i<<)|].sum3 = (segTree[(i<<)|].r - segTree[(i<<)|].l + )*segTree[(i<<)|].lazy3%MOD*segTree[(i<<)|].lazy3%MOD*segTree[(i<<)|].lazy3%MOD;
segTree[i].lazy3 = ;
}
if(segTree[i].lazy1 != || segTree[i].lazy2 != )
{
segTree[i<<].lazy1 = ( segTree[i].lazy2*segTree[i<<].lazy1%MOD + segTree[i].lazy1 )%MOD;
segTree[i<<].lazy2 = segTree[i<<].lazy2*segTree[i].lazy2%MOD;
int sum1,sum2,sum3;
sum1 = (segTree[i<<].sum1*segTree[i].lazy2%MOD + (segTree[i<<].r - segTree[i<<].l + )*segTree[i].lazy1%MOD)%MOD;
sum2 = (segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i<<].sum2 % MOD + *segTree[i].lazy1*segTree[i].lazy2%MOD * segTree[i<<].sum1%MOD + (segTree[i<<].r - segTree[i<<].l + )*segTree[i].lazy1%MOD*segTree[i].lazy1%MOD)%MOD;
sum3 = segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i<<].sum3 % MOD;
sum3 = (sum3 + *segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i<<].sum2) % MOD;
sum3 = (sum3 + *segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[i<<].sum1) % MOD;
sum3 = (sum3 + (segTree[i<<].r - segTree[i<<].l + )*segTree[i].lazy1%MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
segTree[i<<].sum1 = sum1;
segTree[i<<].sum2 = sum2;
segTree[i<<].sum3 = sum3;
segTree[(i<<)|].lazy1 = ( segTree[i].lazy2*segTree[(i<<)|].lazy1%MOD + segTree[i].lazy1 )%MOD;
segTree[(i<<)|].lazy2 = segTree[(i<<)|].lazy2 * segTree[i].lazy2 % MOD;
sum1 = (segTree[(i<<)|].sum1*segTree[i].lazy2%MOD + (segTree[(i<<)|].r - segTree[(i<<)|].l + )*segTree[i].lazy1%MOD)%MOD;
sum2 = (segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[(i<<)|].sum2 % MOD + *segTree[i].lazy1*segTree[i].lazy2%MOD * segTree[(i<<)|].sum1%MOD + (segTree[(i<<)|].r - segTree[(i<<)|].l + )*segTree[i].lazy1%MOD*segTree[i].lazy1%MOD)%MOD;
sum3 = segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[(i<<)|].sum3 % MOD;
sum3 = (sum3 + *segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[(i<<)|].sum2) % MOD;
sum3 = (sum3 + *segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[(i<<)|].sum1) % MOD;
sum3 = (sum3 + (segTree[(i<<)|].r - segTree[(i<<)|].l + )*segTree[i].lazy1%MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
segTree[(i<<)|].sum1 = sum1;
segTree[(i<<)|].sum2 = sum2;
segTree[(i<<)|].sum3 = sum3;
segTree[i].lazy1 = ;
segTree[i].lazy2 = ; }
}
void update(int i,int l,int r,int type,int c)
{
if(segTree[i].l == l && segTree[i].r == r)
{
c %= MOD;
if(type == )
{
segTree[i].lazy1 += c;
segTree[i].lazy1 %= MOD;
segTree[i].sum3 = (segTree[i].sum3 + *segTree[i].sum2%MOD*c%MOD + *segTree[i].sum1%MOD*c%MOD*c%MOD + (segTree[i].r - segTree[i].l + )*c%MOD*c%MOD*c%MOD)%MOD;
segTree[i].sum2 = (segTree[i].sum2 + *segTree[i].sum1%MOD*c%MOD + (segTree[i].r - segTree[i].l + )*c%MOD*c%MOD)%MOD;
segTree[i].sum1 = (segTree[i].sum1 + (segTree[i].r - segTree[i].l + )*c%MOD)%MOD;
}
else if(type == )
{
segTree[i].lazy1 = segTree[i].lazy1*c%MOD;
segTree[i].lazy2 = segTree[i].lazy2*c%MOD;
segTree[i].sum1 = segTree[i].sum1*c%MOD;
segTree[i].sum2 = segTree[i].sum2*c%MOD*c%MOD;
segTree[i].sum3 = segTree[i].sum3*c%MOD*c%MOD*c%MOD;
}
else
{
segTree[i].lazy1 = ;
segTree[i].lazy2 = ;
segTree[i].lazy3 = c%MOD;
segTree[i].sum1 = c*(segTree[i].r - segTree[i].l + )%MOD;
segTree[i].sum2 = c*(segTree[i].r - segTree[i].l + )%MOD*c%MOD;
segTree[i].sum3 = c*(segTree[i].r - segTree[i].l + )%MOD*c%MOD*c%MOD;
}
return;
}
push_down(i);
int mid = (segTree[i].l + segTree[i].r)/;
if(r <= mid)update(i<<,l,r,type,c);
else if(l > mid)update((i<<)|,l,r,type,c);
else
{
update(i<<,l,mid,type,c);
update((i<<)|,mid+,r,type,c);
}
push_up(i);
}
int query(int i,int l,int r,int p)
{
if(segTree[i].l == l && segTree[i].r == r)
{
if(p == )return segTree[i].sum1;
else if(p== )return segTree[i].sum2;
else return segTree[i].sum3;
}
push_down(i);
int mid = (segTree[i].l + segTree[i].r )/;
if(r <= mid)return query(i<<,l,r,p);
else if(l > mid)return query((i<<)|,l,r,p);
else return (query(i<<,l,mid,p)+query((i<<)|,mid+,r,p))%MOD;
} int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m;
while(scanf("%d%d",&n,&m) == )
{
if(n == && m == )break;
build(,,n);
int type,x,y,c;
while(m--)
{
scanf("%d%d%d%d",&type,&x,&y,&c);
if(type == )printf("%d\n",query(,x,y,c));
else update(,x,y,type,c);
}
}
return ;
}
32 / 103 Problem L HDU 4614 Vases and Flowers
很裸的线段树。但是写起来很麻烦。
1~N 的区间,用1表示空的,0表示放了花的。
维护一个sum,就是和
first : 区间最左边的1
last: 区间最右边的1
然后一个更新操作,一个求区间和操作。
查询区间第一个1,和最后一个1.
二分确定区间。
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <string>
#include <math.h>
using namespace std;
const int MAXN = ;
struct Node
{
int l,r;
int sum;
int lazy;
int first;
int last;
}segTree[MAXN*];
void push_up(int i)
{
if(segTree[i].l==segTree[i].r)return;
segTree[i].sum = segTree[i<<].sum+segTree[(i<<)|].sum;
if(segTree[i<<].first != -)segTree[i].first = segTree[i<<].first;
else segTree[i].first = segTree[(i<<)|].first;
if(segTree[(i<<)|].last != -)segTree[i].last = segTree[(i<<)|].last;
else segTree[i].last = segTree[(i<<)].last;
}
void push_down(int i)
{
if(segTree[i].r == segTree[i].l)return;
if(segTree[i].lazy==)
{
segTree[i<<].first = segTree[i<<].l;
segTree[i<<].last = segTree[i<<].r;
segTree[i<<].sum = segTree[i<<].r-segTree[i<<].l+;
segTree[i<<].lazy=;
segTree[(i<<)|].first = segTree[(i<<)|].l;
segTree[(i<<)|].last = segTree[(i<<)|].r;
segTree[(i<<)|].sum = segTree[(i<<)|].r-segTree[(i<<)|].l+;
segTree[(i<<)|].lazy=;
}
if(segTree[i].lazy == -)
{
segTree[i<<].first = -;
segTree[i<<].last = -;
segTree[i<<].sum = ;
segTree[i<<].lazy=-;
segTree[(i<<)|].first = -;
segTree[(i<<)|].last = -;
segTree[(i<<)|].sum = ;
segTree[(i<<)|].lazy=-;
}
segTree[i].lazy = ;
}
void build(int i,int l,int r)
{
segTree[i].l = l;
segTree[i].r = r;
segTree[i].sum = r-l+;
segTree[i].lazy = ;
segTree[i].first = l;
segTree[i].last = r;
if(l==r)return ;
int mid = (l+r)/;
build(i<<,l,mid);
build((i<<)|,mid+,r);
}
void update(int i,int l,int r,int type)
{
if(segTree[i].l == l && segTree[i].r==r)
{
if(type == )
{
if(segTree[i].sum == )return;
segTree[i].sum = ;
segTree[i].lazy = -;
segTree[i].first = -;
segTree[i].last = -;
return;
}
else if(type == )
{
if(segTree[i].sum == segTree[i].r-segTree[i].l+)return;
segTree[i].sum = segTree[i].r-segTree[i].l+;
segTree[i].lazy = ;
segTree[i].first = segTree[i].l;
segTree[i].last = segTree[i].r;
return;
} }
push_down(i);
int mid = (segTree[i].l + segTree[i].r)/;
if(r <= mid)update(i<<,l,r,type);
else if(l > mid)update((i<<)|,l,r,type);
else
{
update(i<<,l,mid,type);
update((i<<)|,mid+,r,type);
}
push_up(i);
}
int sum(int i,int l,int r)
{
if(segTree[i].l == l && segTree[i].r == r)
{
return segTree[i].sum;
}
push_down(i);
int mid = (segTree[i].l + segTree[i].r)/;
if(r <= mid)return sum(i<<,l,r);
else if(l > mid)return sum((i<<)|,l,r);
else return sum((i<<)|,mid+,r)+sum(i<<,l,mid);
}
int n,m;
int query1(int i,int l,int r)
{
if(segTree[i].l == l && segTree[i].r == r)
{
return segTree[i].first;
}
push_down(i);
int mid = (segTree[i].l + segTree[i].r)/;
int ans1,ans2;
if(r <= mid)return query1(i<<,l,r);
else if(l > mid)return query1((i<<)|,l,r);
else
{
ans1 = query1(i<<,l,mid);
if(ans1 != -)return ans1;
return query1((i<<)|,mid+,r);
}
}
int query2(int i,int l,int r)
{
if(segTree[i].l == l && segTree[i].r == r)
{
return segTree[i].last;
}
push_down(i);
int mid = (segTree[i].l + segTree[i].r)/;
int ans1,ans2;
if(r <= mid)return query2(i<<,l,r);
else if(l > mid)return query2((i<<)|,l,r);
else
{
ans1 = query2((i<<)|,mid+,r);
if(ans1 != -)return ans1;
return query2(i<<,l,mid);
}
}
int bisearch(int A,int F)
{
if(sum(,A,n)==)return -;
if(sum(,A,n)<F)return n;
int l= A,r = n;
int ans=A;
while(l<=r)
{
int mid = (l+r)/;
if(sum(,A,mid)>=F)
{
ans = mid;
r = mid-;
}
else l = mid+;
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
build(,,n);
int op,u,v;
while(m--)
{
scanf("%d%d%d",&op,&u,&v);
if(op == )
{
u++;
int t = bisearch(u,v);
//printf("t:%d\n",t);
if(t==-)
{
printf("Can not put any one.\n");
continue;
}
printf("%d %d\n",query1(,u,t)-,query2(,u,t)-);
update(,u,t,);
}
else
{
u++;v++;
//printf("sum:%d\n",sum(1,u,v));
printf("%d\n",v-u+-sum(,u,v));
update(,u,v,);
}
}
printf("\n");
}
return ;
}
29 / 139 Problem M HDU 4553 约会安排
//============================================================================
// Name : C.cpp
// Author :
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================ #include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <queue>
#include <set>
#include <vector>
#include <string>
#include <math.h>
using namespace std;
const int MAXN=;
struct Node
{
int l,r;
int Max,Lmax,Rmax;
int Max1,Lmax1,Rmax1;
}segTree[MAXN*];
void push_up(int x)
{
if(segTree[x].l==segTree[x].r)return;
int lson=*x;
int rson=*x+; segTree[x].Lmax=segTree[lson].Lmax;
if(segTree[lson].Lmax==segTree[lson].r-segTree[lson].l+)segTree[x].Lmax+=segTree[rson].Lmax;
segTree[x].Rmax=segTree[rson].Rmax;
if(segTree[rson].Rmax==segTree[rson].r-segTree[rson].l+)segTree[x].Rmax+=segTree[lson].Rmax;
segTree[x].Max=max(segTree[lson].Max,segTree[rson].Max);
segTree[x].Max=max(segTree[x].Max,max(segTree[x].Lmax,segTree[x].Rmax));
segTree[x].Max=max(segTree[x].Max,segTree[lson].Rmax+segTree[rson].Lmax); segTree[x].Lmax1=segTree[lson].Lmax1;
if(segTree[lson].Lmax1==segTree[lson].r-segTree[lson].l+)segTree[x].Lmax1+=segTree[rson].Lmax1;
segTree[x].Rmax1=segTree[rson].Rmax1;
if(segTree[rson].Rmax1==segTree[rson].r-segTree[rson].l+)segTree[x].Rmax1+=segTree[lson].Rmax1;
segTree[x].Max1=max(segTree[lson].Max1,segTree[rson].Max1);
segTree[x].Max1=max(segTree[x].Max1,max(segTree[x].Lmax1,segTree[x].Rmax1));
segTree[x].Max1=max(segTree[x].Max1,segTree[lson].Rmax1+segTree[rson].Lmax1);
}
void push_down(int x)
{
if(segTree[x].l==segTree[x].r)return;
int lson=*x,rson=*x+;
if(segTree[x].Max==)
{
segTree[lson].Max=segTree[lson].Lmax=segTree[lson].Rmax=;
segTree[rson].Max=segTree[rson].Lmax=segTree[rson].Rmax=;
}
if(segTree[x].Max==segTree[x].r-segTree[x].l+)
{
segTree[lson].Max=segTree[lson].Lmax=segTree[lson].Rmax=segTree[lson].r-segTree[lson].l+;
segTree[rson].Max=segTree[rson].Lmax=segTree[rson].Rmax=segTree[rson].r-segTree[rson].l+;
} if(segTree[x].Max1==)
{
segTree[lson].Max1=segTree[lson].Lmax1=segTree[lson].Rmax1=;
segTree[rson].Max1=segTree[rson].Lmax1=segTree[rson].Rmax1=;
}
if(segTree[x].Max1==segTree[x].r-segTree[x].l+)
{
segTree[lson].Max1=segTree[lson].Lmax1=segTree[lson].Rmax1=segTree[lson].r-segTree[lson].l+;
segTree[rson].Max1=segTree[rson].Lmax1=segTree[rson].Rmax1=segTree[rson].r-segTree[rson].l+;
} }
void Build(int i,int l,int r)
{
segTree[i].l=l;
segTree[i].r=r;
segTree[i].Max=segTree[i].Lmax=segTree[i].Rmax=r-l+;
segTree[i].Max1=segTree[i].Lmax1=segTree[i].Rmax1=r-l+;
if(l==r)return;
int mid=(l+r)/;
Build(i<<,l,mid);
Build((i<<)|,mid+,r);
}
int query(int i,int x)
{
if(segTree[i].Max<x)return ;
if(segTree[i].Lmax>=x)return segTree[i].l;
if(segTree[i<<].Max>=x)return query(i<<,x);
if(segTree[i<<].Rmax+segTree[(i<<)|].Lmax>=x)return segTree[i<<].r-segTree[i<<].Rmax+;
return query((i<<)|,x);
}
int query1(int i,int x)
{
if(segTree[i].Max1<x)return ;
if(segTree[i].Lmax1>=x)return segTree[i].l;
if(segTree[i<<].Max1>=x)return query1(i<<,x);
if(segTree[i<<].Rmax1+segTree[(i<<)|].Lmax1>=x)return segTree[i<<].r-segTree[i<<].Rmax1+;
return query1((i<<)|,x);
}
void update(int i,int l,int r)
{
if(segTree[i].l==l && segTree[i].r==r)
{
segTree[i].Max=segTree[i].Lmax=segTree[i].Rmax=segTree[i].r-segTree[i].l+;
segTree[i].Max1=segTree[i].Lmax1=segTree[i].Rmax1=segTree[i].r-segTree[i].l+;
return;
}
push_down(i);
int mid=(segTree[i].l+segTree[i].r)/;
if(r<=mid)update(i<<,l,r);
else if(l>mid) update((i<<)|,l,r);
else
{
update(i<<,l,mid);
update((i<<)|,mid+,r);
}
push_up(i);
}
void zhan1(int i,int l,int r)
{
if(segTree[i].l==l && segTree[i].r==r)
{
segTree[i].Max=segTree[i].Lmax=segTree[i].Rmax=;
return;
}
push_down(i);
int mid=(segTree[i].l+segTree[i].r)/;
if(r<=mid)zhan1(i<<,l,r);
else if(l>mid) zhan1((i<<)|,l,r);
else
{
zhan1(i<<,l,mid);
zhan1((i<<)|,mid+,r);
}
push_up(i);
}
void zhan2(int i,int l,int r)
{
if(segTree[i].l==l && segTree[i].r==r)
{
segTree[i].Max=segTree[i].Lmax=segTree[i].Rmax=;
segTree[i].Max1=segTree[i].Lmax1=segTree[i].Rmax1=;
return;
}
push_down(i);
int mid=(segTree[i].l+segTree[i].r)/;
if(r<=mid)zhan2(i<<,l,r);
else if(l>mid) zhan2((i<<)|,l,r);
else
{
zhan2(i<<,l,mid);
zhan2((i<<)|,mid+,r);
}
push_up(i);
} int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;
int n,m;
int l,r;
int x;
char op[];
scanf("%d",&T);
int iCase=;
while(T--)
{
iCase++;
printf("Case %d:\n",iCase);
scanf("%d%d",&n,&m);
Build(,,n);
while(m--)
{
scanf("%s",op);
if(op[]=='D')
{
scanf("%d",&x);
int tmp=query(,x);
if(tmp==)printf("fly with yourself\n");
else
{
zhan1(,tmp,tmp+x-);
printf("%d,let's fly\n",tmp);
}
}
else if(op[]=='N')
{
scanf("%d",&x);
int tmp=query(,x);
if(tmp!=)
{
zhan2(,tmp,tmp+x-);
printf("%d,don't put my gezi\n",tmp);
continue;
}
tmp=query1(,x);
if(tmp!=)
{
zhan2(,tmp,tmp+x-);
printf("%d,don't put my gezi\n",tmp);
continue;
}
printf("wait for me\n");
}
else
{
scanf("%d%d",&l,&r);
printf("I am the hope of chinese chengxuyuan!!\n");
update(,l,r);
}
}
}
return ;
}
35 / 52 Problem N POJ 1177 Picture
总体思路:
1.沿X轴离散化建树
2.按Y值从小到大排序平行与X轴的边,然后顺序处理
如果遇到矩形下面那条边则插入到线段树中,遇到矩形上面的边则将相应的边删除掉
根据线段树当前的状态统计长度
第二点是本题的核心思想,偶再举个例:
第一次求出的部分很好理解.
第二次求出的为什么会少了中间那部分.那是因为插入的新线段覆盖了第一条,此时线段树返回的长度是新的那一条的长度,将这个值再减去上次的就少了中间那部分
第三次因为是矩形的上边,所以要删除在那条长的线段.此时的线段树返回的则是第一次的长度,将此值减去第二次返回值,再取其负值就是红色X轴那部分了
最后那条X轴的,再补上就行了.
需要注意的就是离散化以后一定要去掉重复元素,否则会出错的。
ps:不懂这种离散化的时候为什么去除重复元素?好像懂了一点点。。不过还是先记住吧,日后有机会再细细研究。
/*
POJ 1177
矩形周长并,求轮廓周长
这题可以不离散化做的,我做的是离散化以后的
这题和矩形面积并有类似的地方
把矩形变成一条条平行于x轴的线段(当然弄成平行于y轴的也是可以的)
要累加的一个是覆盖的线段长度的变化,还有就是竖直的线段。
离散化以后一定要进行去掉重复的点,因为会影响后面合并的时候。
STL中的unique()函数可以快速去掉相同元素
*/ #include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAXN=;
struct Node
{
int l,r;
int cnt;//有效长度
int lf,rf;//实际的左右端点
int numseg;//分支数,一个分支对应两条竖线
int c;//记录覆盖情况
bool lcover,rcover;
}segTree[MAXN*];
struct Line
{
int y;
int x1,x2;
int f;
}line[MAXN];
bool cmp(Line a,Line b)
{
return a.y<b.y;
}
int x[MAXN];
void Build(int i,int l,int r)
{
segTree[i].l=l;
segTree[i].r=r;
segTree[i].lf=x[l];
segTree[i].rf=x[r];
segTree[i].cnt=;
segTree[i].numseg=;
segTree[i].c=;
segTree[i].lcover=segTree[i].rcover=false;
if(l+==r)return;
int mid=(l+r)/;
Build(i<<,l,mid);
Build((i<<)|,mid,r);
}
void calen(int i)
{
if(segTree[i].c>)
{
segTree[i].cnt=segTree[i].rf-segTree[i].lf;
segTree[i].numseg=;
segTree[i].lcover=segTree[i].rcover=true;
return;
}
if(segTree[i].l+==segTree[i].r)
{
segTree[i].cnt=;
segTree[i].numseg=;
segTree[i].lcover=segTree[i].rcover=false;
}
else
{
segTree[i].cnt=segTree[i<<].cnt+segTree[(i<<)|].cnt;
segTree[i].lcover=segTree[i<<].lcover;
segTree[i].rcover=segTree[(i<<)|].rcover;
segTree[i].numseg=segTree[i<<].numseg+segTree[(i<<)|].numseg;
if(segTree[i<<].rcover&&segTree[(i<<)|].lcover)segTree[i].numseg--;
}
}
void update(int i,Line e)
{
if(segTree[i].lf==e.x1&&segTree[i].rf==e.x2)
{
segTree[i].c+=e.f;
calen(i);
return;
}
if(e.x2<=segTree[i<<].rf)update(i<<,e);
else if(e.x1>=segTree[(i<<)|].lf)update((i<<)|,e);
else
{
Line temp=e;
temp.x2=segTree[i<<].rf;
update(i<<,temp);
temp=e;
temp.x1=segTree[(i<<)|].lf;
update((i<<)|,temp);
}
calen(i);
}
int main()
{
int x1,y1,x2,y2;
int n;
while(scanf("%d",&n)==)
{
int t=;
for(int i=;i<n;i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
line[t].x1=x1;
line[t].x2=x2;
line[t].y=y1;
line[t].f=;
x[t++]=x1;
line[t].x1=x1;
line[t].x2=x2;
line[t].y=y2;
line[t].f=-;
x[t++]=x2;
}
sort(line,line+t,cmp); sort(x,x+t);
int m=unique(x,x+t)-x;//合并相同元素,这里一点要合并相同元素,否则会WA.
Build(,,m-);
int ans=;
int last=;
for(int i=;i<t-;i++)
{
update(,line[i]);
ans+=segTree[].numseg**(line[i+].y-line[i].y);
ans+=abs(segTree[].cnt-last);
last=segTree[].cnt;
}
update(,line[t-]);
ans+=abs(segTree[].cnt-last);
printf("%d\n",ans);
}
return ;
}
37 / 67 Problem O HDU 1255 覆盖的面积
d.求面积交
hint.解题报告见之前博客
40 / 88 Problem P HDU 1542 Atlantis
d.求面积并,比求面积交简单
/*
POJ 1151 Atlantis
求矩形并的面积(线段树+离散化)
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 201
struct Node
{
int l,r;//线段树的左右整点
int c;//c用来记录重叠情况
double cnt,lf,rf;//
//cnt用来计算实在的长度,rf,lf分别是对应的左右真实的浮点数端点
}segTree[MAXN*];
struct Line
{
double x,y1,y2;
int f;
}line[MAXN];
//把一段段平行于y轴的线段表示成数组 ,
//x是线段的x坐标,y1,y2线段对应的下端点和上端点的坐标
//一个矩形 ,左边的那条边f为1,右边的为-1,
//用来记录重叠情况,可以根据这个来计算,nod节点中的c bool cmp(Line a,Line b)//sort排序的函数
{
return a.x < b.x;
} double y[MAXN];//记录y坐标的数组
void Build(int t,int l,int r)//构造线段树
{
segTree[t].l=l;segTree[t].r=r;
segTree[t].cnt=segTree[t].c=;
segTree[t].lf=y[l];
segTree[t].rf=y[r];
if(l+==r) return;
int mid=(l+r)>>;
Build(t<<,l,mid);
Build(t<<|,mid,r);//递归构造
}
void calen(int t)//计算长度
{
if(segTree[t].c>)
{
segTree[t].cnt=segTree[t].rf-segTree[t].lf;
return;
}
if(segTree[t].l+==segTree[t].r) segTree[t].cnt=;
else segTree[t].cnt=segTree[t<<].cnt+segTree[t<<|].cnt;
}
void update(int t,Line e)//加入线段e,后更新线段树
{
if(e.y1==segTree[t].lf&&e.y2==segTree[t].rf)
{
segTree[t].c+=e.f;
calen(t);
return;
}
if(e.y2<=segTree[t<<].rf) update(t<<,e);
else if(e.y1>=segTree[t<<|].lf) update(t<<|,e);
else
{
Line tmp=e;
tmp.y2=segTree[t<<].rf;
update(t<<,tmp);
tmp=e;
tmp.y1=segTree[t<<|].lf;
update(t<<|,tmp);
}
calen(t);
}
int main()
{
int i,n,t,iCase=;
double x1,y1,x2,y2;
while(scanf("%d",&n),n)
{
iCase++;
t=;
for(i=;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
line[t].x=x1;
line[t].y1=y1;
line[t].y2=y2;
line[t].f=;
y[t]=y1;
t++;
line[t].x=x2;
line[t].y1=y1;
line[t].y2=y2;
line[t].f=-;
y[t]=y2;
t++;
}
sort(line+,line+t,cmp);
sort(y+,y+t);
Build(,,t-);
update(,line[]);
double res=;
for(i=;i<t;i++)
{
res+=segTree[].cnt*(line[i].x-line[i-].x);
update(,line[i]);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",iCase,res);
//看来POJ上%.2f可以过,%.2lf却不行了
}
return ;
}
7 / 15 Problem Q HDU 3642 Get The Treasury
求立方体相交至少3次的体积。
枚举z
然后求矩形面积交。
常规的线段树题目。
较麻烦
/*
*HDU 3642
给定一些长方体,求这些长方体相交至少3次的体积
z坐标的绝对值不超过500,所以枚举z坐标,然后求矩形面积并
*/ #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN=;
struct Node
{
int l,r;
int lf,rf;//实际的左右端点
int c;
int once,twice,more;
}segTree[MAXN*];
int y[MAXN];
int z[MAXN];
struct Line
{
int x;
int y1,y2;
int z1,z2;//这两个是枚举的时候判断使用的
int f;
}line[MAXN];
bool cmp(Line a,Line b)
{
return a.x<b.x;
}
void Build(int i,int l,int r)
{
segTree[i].l=l;
segTree[i].r=r;
segTree[i].lf=y[l];
segTree[i].rf=y[r];
segTree[i].c=;
segTree[i].once=segTree[i].twice=segTree[i].more=;
if(r==l+)return;
int mid=(l+r)>>;
Build(i<<,l,mid);
Build((i<<)|,mid,r);
}
void push_up(int i)
{
if(segTree[i].c>)
{
segTree[i].more=segTree[i].rf-segTree[i].lf;
segTree[i].once=segTree[i].twice=;
}
else if(segTree[i].c==)
{
if(segTree[i].l+==segTree[i].r)//叶子结点
{
segTree[i].more=;
segTree[i].twice=segTree[i].rf-segTree[i].lf;
segTree[i].once=;
return;
}
segTree[i].more=segTree[i<<].once+segTree[i<<].twice+segTree[i<<].more
+segTree[(i<<)|].once+segTree[(i<<)|].twice+segTree[(i<<)|].more;
segTree[i].twice=segTree[i].rf-segTree[i].lf-segTree[i].more;
segTree[i].once=;
}
else if(segTree[i].c==)
{
if(segTree[i].l+==segTree[i].r)
{
segTree[i].more=;
segTree[i].twice=;
segTree[i].once=segTree[i].rf-segTree[i].lf;
return;
}
segTree[i].more=segTree[i<<].more+segTree[i<<].twice
+segTree[(i<<)|].more+segTree[(i<<)|].twice;
segTree[i].twice=segTree[i<<].once+segTree[(i<<)|].once;
segTree[i].once=segTree[i].rf-segTree[i].lf-segTree[i].more-segTree[i].twice;
}
else
{
if(segTree[i].l+==segTree[i].r)
{
segTree[i].more=segTree[i].once=segTree[i].twice=;
return;
}
segTree[i].more=segTree[i<<].more+segTree[(i<<)|].more;
segTree[i].twice=segTree[i<<].twice+segTree[(i<<)|].twice;
segTree[i].once=segTree[i<<].once+segTree[(i<<)|].once;
}
}
void update(int i,Line e)
{
if(segTree[i].lf>=e.y1 && segTree[i].rf<=e.y2)
{
segTree[i].c+=e.f;
push_up(i);
return;
}
if(e.y2<=segTree[i<<].rf) update(i<<,e);
else if(e.y1>=segTree[(i<<)|].lf) update((i<<)|,e);
else
{
Line temp=e;
temp.y2=segTree[i<<].rf;
update(i<<,temp);
temp=e;
temp.y1=segTree[(i<<)|].lf;
update((i<<)|,temp);
}
push_up(i);
}
Line temp[MAXN];
int main()
{
int T;
int n;
int x1,y1,z1,x2,y2,z2;
scanf("%d",&T);
int iCase=;
while(T--)
{
iCase++;
scanf("%d",&n);
int t=;
for(int i=;i<n;i++)
{
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
line[t].x=x1;
line[t].y1=y1;
line[t].y2=y2;
line[t].z1=z1;
line[t].z2=z2;
line[t].f=;
y[t]=y1;
z[t++]=z1; line[t].x=x2;
line[t].y1=y1;
line[t].y2=y2;
line[t].z1=z1;
line[t].z2=z2;
line[t].f=-;
y[t]=y2;
z[t++]=z2;
}
sort(line,line+t,cmp);
sort(y,y+t);
int t1=unique(y,y+t)-y;
Build(,,t1-);
sort(z,z+t);
int t2=unique(z,z+t)-z;
long long ans=;
long long area=;
for(int i=;i<t2-;i++)
{
int m=;
for(int j=;j<t;j++)
if(line[j].z1<=z[i]&&line[j].z2>z[i])
temp[m++]=line[j];
area=;
update(,temp[]);
for(int j=;j<m;j++)
{
area+=(long long)segTree[].more*(temp[j].x-temp[j-].x);
update(,temp[j]);
}
ans+=area*(z[i+]-z[i]);
}
printf("Case %d: %I64d\n",iCase,ans);
}
return ;
}
[kuangbin带你飞]专题七 线段树的更多相关文章
- 【算法系列学习】线段树vs树状数组 单点修改,区间查询 [kuangbin带你飞]专题七 线段树 A - 敌兵布阵
https://vjudge.net/contest/66989#problem/A 单点修改,区间查询 方法一:线段树 http://www.cnblogs.com/kuangbin/archive ...
- 【算法系列学习】线段树 区间修改,区间求和 [kuangbin带你飞]专题七 线段树 C - A Simple Problem with Integers
https://vjudge.net/contest/66989#problem/C #include<iostream> #include<cstdio> #include& ...
- 【算法系列学习】线段树 单点覆盖,区间查询最大值 [kuangbin带你飞]专题七 线段树 B - I Hate It
https://vjudge.net/contest/66989#overview #include<iostream> #include<cstdio> #include&l ...
- [kuangbin带你飞]专题1-23题目清单总结
[kuangbin带你飞]专题1-23 专题一 简单搜索 POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 Fli ...
- 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开
[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...
- [kuangbin带你飞]专题八 生成树 - 次小生成树部分
百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么 ...
- [kuangbin带你飞]专题十 匹配问题
A-L 二分匹配 M-O 二分图多重匹配 P-Q 二分图最大权匹配 R-S 一般图匹配带花树 模板请自己找 ID Origin Title 61 / 72 Problem A HD ...
- [kuangbin带你飞]专题十 匹配问题 一般图匹配
过去做的都是二分图匹配 即 同一个集合里的点 互相不联通 但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决 带花树模板 用来处理一个无向图上的最大匹配 看了一会还是不懂 抄了一遍 ...
- [kuangbin带你飞]专题六 最小生成树
学习最小生成树已经有一段时间了 做一些比较简单的题还算得心应手..花了三天的时间做完了kuangbin的专题 写一个题解出来记录一下(虽然几乎都是模板题) 做完的感想:有很多地方都要注意 n == 1 ...
随机推荐
- PouchDB:可随时同步的开源JavaScript数据库
PouchDB是一个开源的JavaScript数据库,可以运行在浏览器中.PouchDB的数据存储.处理方式受到了Apache CouchDB的启发(CouchDB是一个面向文档的数据库,可通过Jav ...
- 【转】C# Winform打包部署时添加注册表信息实现开机启动
使用VS自带的打包模块可以很方便的对项目进行打包部署,同时我们也可以在安装部署时操作注册表实现开机启动软件.具体实现如下: 1.添加安装部署项目后,鼠标右键安装项目->视图->注册表,HK ...
- Why doesn't Genymotion run on Windows 10?
To date, VirtualBox is not yet fully compatible with Windows 10. As Genymotion relies on the use of ...
- maven时候Embedded error: error in opening zip file
maven时候Embedded error: error in opening zip file 用 mvn clean install -Dmaven.test.skip=true -Denv=re ...
- 【mysql】MySQL存储IP地址
为什么要问如何存储IP 首先就来阐明一下部分人得反问:为什么要问IP得怎样存,直接varchar类型不就得了吗? 其实做任何程序设计都要在功能实现的基础上最大限度的优化性能.而数据库设计是程序设计中不 ...
- 05文件与IO
这节主要学习了read.write.lseek.目录访问(opendir.readdir.closedir)这几个系统调用及其简单的应用. 一旦有了与一个打开文件描述相连的文件描述符,只要该文件是用O ...
- bzoj3007: 拯救小云公主
Description 英雄又即将踏上拯救公主的道路…… 这次的拯救目标是——爱和正义的小云公主. 英雄来到boss的洞穴门口,他一下子就懵了,因为面前不只是一只boss,而是 ...
- idea系列新版注册模式
http://idea.qinxi1992.cn/ 楼上被列入黑名单,用 http://114.215.133.70:41017/
- sqlite3移植到arm linux
1,环境: 软件:linux:2.6.38 硬件:6410 交叉编译工具:arm-linux-gcc 也适用于其他linux平台. 2,步骤: 1>下载sqlite3源码包: http://ww ...
- flash读取XML节点内容以及节点属性
原文地址:http://hi.baidu.com/yqzdm/item/f95fd9d24679d916d90e44c9 一.xml的写法: 这里的xml只是在有限范围内的了解,限于写一些简单的用于f ...