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]里所有数的和。

关键就是一个数开根号几次后很快就可以变成1了。
如果都是1就不需要往下更新了。
还有就是输入的X,Y大小是不一定的,,这个坑了好久
/*
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

题意是一条线上的点,D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数(即连续的完好的村庄的个数),R是恢复上一次破坏的点。
线段树结点 设置一个  ll 记录区间左端点开始的最大连续个数,  rl 记录区间右端点开始的最大的连续个数,
ml表示该区间最大的连续点的个数。
主要是更新和查询两个操作。
有点像分治的意思,大区间的最优解由两个小区间的最优解以及小区间中间相连的那部分决定。
 
/*
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 约会安排

就是线段树。。。
进行两段区间合并操作
c.不得不说代码太帅了。。我是想不到这么写的。。学习了
//============================================================================
// 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带你飞]专题七 线段树的更多相关文章

  1. 【算法系列学习】线段树vs树状数组 单点修改,区间查询 [kuangbin带你飞]专题七 线段树 A - 敌兵布阵

    https://vjudge.net/contest/66989#problem/A 单点修改,区间查询 方法一:线段树 http://www.cnblogs.com/kuangbin/archive ...

  2. 【算法系列学习】线段树 区间修改,区间求和 [kuangbin带你飞]专题七 线段树 C - A Simple Problem with Integers

    https://vjudge.net/contest/66989#problem/C #include<iostream> #include<cstdio> #include& ...

  3. 【算法系列学习】线段树 单点覆盖,区间查询最大值 [kuangbin带你飞]专题七 线段树 B - I Hate It

    https://vjudge.net/contest/66989#overview #include<iostream> #include<cstdio> #include&l ...

  4. [kuangbin带你飞]专题1-23题目清单总结

    [kuangbin带你飞]专题1-23 专题一 简单搜索 POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 Fli ...

  5. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

  6. [kuangbin带你飞]专题八 生成树 - 次小生成树部分

    百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么 ...

  7. [kuangbin带你飞]专题十 匹配问题

        A-L 二分匹配 M-O 二分图多重匹配 P-Q 二分图最大权匹配 R-S 一般图匹配带花树 模板请自己找     ID Origin Title   61 / 72 Problem A HD ...

  8. [kuangbin带你飞]专题十 匹配问题 一般图匹配

    过去做的都是二分图匹配 即 同一个集合里的点 互相不联通 但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决 带花树模板 用来处理一个无向图上的最大匹配 看了一会还是不懂  抄了一遍 ...

  9. [kuangbin带你飞]专题六 最小生成树

    学习最小生成树已经有一段时间了 做一些比较简单的题还算得心应手..花了三天的时间做完了kuangbin的专题 写一个题解出来记录一下(虽然几乎都是模板题) 做完的感想:有很多地方都要注意 n == 1 ...

随机推荐

  1. js列表分页

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. python之chardet库

    chardet库是python的字符编码检测器,能够检测出各种编码的类型,例如: import chardet import urllib.request testdata = urllib.requ ...

  3. RMAN备份与恢复之不完全恢复

    要点:对于RMAN的不完全恢复,有如下步骤: 1)加载数据到mount状态(建议恢复前先做备份) 2)为高并发分配多个通道 3)还原所有(所需)的数据文件 4)使用until time,until s ...

  4. R提高篇(三): 数据管理一

    目录: 创建新变量 变量重编码 日期值 数据排序 数据集合并 数据子集 随机取样 创建新变量 算术运算函数:x%%y [求余 x mod y,  5%%2的结果为1], x%/%y  [整数除法,5% ...

  5. R(八): R分词统计-老九门

    分析文本内容基本的步骤:提取文本中的词语 -> 统计词语频率 -> 词频属性可视化.词频:能反映词语在文本中的重要性,一般越重要的词语,在文本中出现的次数就会越多.词云:让词语的频率属性可 ...

  6. CSS命名规则

    头:header  内容:content/container  尾:footer  导航:nav  侧栏:sidebar 栏目:column  页面外围控制整体布局宽度:wrapper  左右中:le ...

  7. openstack(liberty):部署实验平台(二,简单版本软件安装 part1)

    软件安装过程中,考虑到现在是一个实验环境,且也考虑到规模不大,还有,网络压力不会大,出于简单考虑,将各个节点的拓扑结构改了一下,主要体现在网络节点和控制节点并在了一起.在一个服务器上安装! 到目前位置 ...

  8. MySQL加载并执行SQL脚本文件

    第一种方法: 命令行下(未连接数据库) ,输入 mysql -h localhost -u root -p123456 < C:\db.sql 第二种方法: 命令行下(已连接数据库,此时的提示符 ...

  9. Linux文件系统Ext2,Ext3,Ext4性能大比拼

    Linux kernel 自 2.6.28 开始正式支持新的文件系统 Ext4. Ext4 是 Ext3 的改进版,修改了 Ext3 中部分重要的数据结构,而不仅仅像 Ext3 对 Ext2 那样,只 ...

  10. golang的验证码相关的库

    识别库 https://github.com/goghcrow/capture_easy 生成验证码的库 https://github.com/hanguofeng/gocaptcha 生成图片水印 ...