您的位置:首页 > 其它

2017暑假集训 div1 线段树(2)

2017-07-14 10:22 543 查看
HDU 4027

题意:给一串数字,两种操作,操作1:区间所有数字开根号,操作二:求区间和

做法:线段树即可,但进行操作1 时先判断一下是否区间和为它的长度,如果是就可以不用更改了(没有这个会T)

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <cmath>
#define lson rt<<1,begin,mid
#define rson rt<<1|1,mid+1,end
using namespace std;
typedef long long ll;
ll tree[100005*4];
void pushup(int rt)
{
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}

void build(int rt,int begin,int end)
{
if(begin==end)
{
scanf("%I64d",&tree[rt]);
return;
}
int mid=(begin+end)>>1;
build(lson) ; build(rson);
pushup(rt);
}

void updata(int rt,int begin,int end,int l,int r)
{
if(begin==end)
{
tree[rt]=sqrt(tree[rt]);
return;
}
int mid=(begin+end)>>1;
if(mid>=l) updata(lson,l,r);
if(r>mid)  updata(rson,l,r);
pushup(rt);
}

ll query(int rt,int begin,int end,int l,int r)
{
if(begin>=l&&r>=end)
{
return tree[rt];
}
ll ans=0;
int mid=(begin+end)>>1;
if(mid>=l) ans+=query(lson,l,r);
if(r>mid)  ans+=query(rson,l,r);
return ans;
}

int main()
{
int n;
int t=0;
while(scanf("%d",&n)!=EOF)
{
build(1,1,n);
int m;
scanf("%d",&m);
printf("Case #%d:\n",++t);
while(m--)
{
int op,a,b;
scanf("%d%d%d",&op,&a,&b);
if(a>b) swap(a,b);
if(op==0)
{
if(query(1,1,n,a,b)!=b-a+1)
updata(1,1,n,a,b);
}
else
{
printf("%I64d\n",query(1,1,n,a,b));
}
}
printf("\n");
}
return 0;
}


HDU 1540

题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少
做法:正解是线段树的合并!!!
           但其实stl set判断当前点左右两边被摧毁的距离也可以(注意加入0,和n+1)边界

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stack>
#include <string.h>
#include <set>
using namespace std;
int n,m;
set<int> myset;
stack<int> d;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
while(!d.empty()) d.pop();
myset.clear();
myset.insert(0);
myset.insert(n+1);
set<int>::iterator l,r;
char str[10];
while(m--)
{
scanf("%s",str);
if(str[0]=='D')
{
int a;
scanf("%d",&a);
myset.insert(a); d.push(a);
}
else if(str[0]=='R')
{
if(d.empty()) continue;
int a=d.top(); d.pop();
myset.erase(a);
}
else
{
int a; scanf("%d",&a);
if(myset.count(a)!=0) printf("0\n");
else
{
l=myset.lower_bound(a);
r=myset.upper_bound(a);
l--;
printf("%d\n",*r-*l-1);
}
}
}
}
return 0;
}


HDU 3974

题意:
一个公司里面每个员工都有一个顶头上司,一旦给某个员工分配任务后,这个员工以及该员工的所有下属都在做该任务。 
    有若干操作,分配给员工任务以及查询该员工正在执行的任务。 
做法:首先线段树是很容易想到的,那关键是怎么在树上跑线段树,其实我们可以先用出入度找出树的根,然后DFS找出dfs序,一个点两次出现的中间点都是该点的子孙!!!

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define lson rt<<1,begin,mid
#define rson rt<<1|1,mid+1,end
const int maxn=50100*2;
int tree[maxn<<4];

void pushdown(int rt)
{
if(tree[rt]!=-1)
{
tree[rt<<1]=tree[rt<<1|1]=tree[rt];
tree[rt]=-1;
}
}

void updata(int rt,int begin,int end,int l,int r,int x)
{
if(begin>=l&&r>=end)
{
tree[rt]=x;
return ;
}
pushdown(rt);
int mid=(begin+end)>>1;
if(mid>=l) updata(lson,l,r,x);
if(r>mid)  updata(rson,l,r,x);
}

int query(int rt,int begin,int end,int pos)
{
if(begin==end)
{
return tree[rt];
}
pushdown(rt);
int mid=(begin+end)>>1;
if(mid>=pos) return query(lson,pos);
else return query(rson,pos);
}

int n,m;
int head[maxn],cnt=0;
struct node
{
int to,next;
}edge[maxn];
void add(int u,int v)
{
edge[cnt].next=head[u]; edge[cnt].to=v; head[u]=cnt++;
}

int in[maxn];

int fis[maxn],num=0;
int sec[maxn];

void dfs(int pos)
{
fis[pos]=num++;
for(int i=head[pos];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(fis[v]==-1)
{
dfs(v);
}
}
sec[pos]=num++;

}

int main()
{
int T,kiss=1;
scanf("%d",&T);
while(T--)
{
memset(head,-1,sizeof(head)); cnt=0;
memset(fis,-1,sizeof(fis)); num=1;
memset(tree,-1,sizeof(tree));
scanf("%d",&n);

for(int i=1;i<=n;++i) in[i]=0;

for(int i=1;i<n;++i)
{
int a,b;
scanf("%d%d",&a,&b);
add(b,a);
in[a]++;
}
int root;
for(int i=1;i<=n;++i)
{
if(in[i]==0) { root=i;  break;}
}
dfs(root);
printf("Case #%d:\n",kiss++);
scanf("%d",&m);
char str;
while(m--)
{
scanf(" %c",&str);
if(str=='C')
{
int a;
scanf("%d",&a);
printf("%d\n",query(1,1,2*n,fis[a]));
}
else if(str=='T')
{
int x,y;
scanf("%d%d",&x,&y);
updata(1,1,2*n,fis[x],sec[x],y);
}
}
}
return 0;
}


HDU 4578
题意:一开始有n个为0的数,一共有四种操作:区间[l,r]内的数全部加c。区间[l,r]内的数全部乘c。区间[l,r]内的数全部初始为c。询问区间[l,r]内所有数的P次方之和

做法:线段树,每个树节点有 sum1,2,3,分别表示 1,2,3次方的和。lazy数组有 muit 和 add 表示没有乘的和没有加的。 每次 操作时候 把点看做 ax+b ,然后根据数学可以由 1,2次方更新三次方,由1次方可以更新出2次方,由加法可以更新出1 次方。注意 : 更新的时候先把 ax算出来 再把b 加进去 ,更新次方和的时候先 3, 再 2,最后 1

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#define lson rt<<1 ,begin ,mid
#define rson rt<<1|1 , mid+1 ,end
using namespace std;
const int mod=10007;
struct node
{
int add;
int muit;
int sum[3];
}tree[100005*8];

void cal(int rt,int muil,int add,int len)
{
tree[rt].sum[0] = tree[rt].sum[0] * muil % mod;
tree[rt].sum[1] = tree[rt].sum[1] * muil % mod * muil % mod ;
tree[rt].sum[2] = tree[rt].sum[2] * muil % mod * muil % mod * muil % mod ;

tree[rt].muit = (tree[rt].muit * muil) % mod;
tree[rt].add  = ((tree[rt].add * muil ) % mod + add ) % mod;

tree[rt].sum[2] = (tree[rt].sum[2] + len * add % mod * add % mod * add % mod) % mod
4000
;
tree[rt].sum[2] = (tree[rt].sum[2] + 3* tree[rt].sum[0] % mod * add %mod *add %mod  ) % mod;
tree[rt].sum[2] = (tree[rt].sum[2] + 3 * tree[rt].sum[1] %mod *add % mod) % mod;

tree[rt].sum[1] = (tree[rt].sum[1] + 2* tree[rt].sum[0] %mod * add % mod) % mod ;
tree[rt].sum[1] = (tree[rt].sum[1] + len * add % mod *add % mod) % mod;

tree[rt].sum[0] = (tree[rt].sum[0] + add * len % mod) %mod;
}

void pushup(int rt)
{
for(int i=0;i<3;++i)  tree[rt].sum[i] = ( tree[rt<<1].sum[i] + tree[rt<<1|1].sum[i] ) %mod;
}

void pushdown(int rt,int k)
{
if(tree[rt].add ==0 && tree[rt] .muit ==1) return;
if(k==1) return ;
cal(rt<<1,tree[rt].muit,tree[rt].add,k-k/2);
cal(rt<<1|1,tree[rt].muit,tree[rt].add,k/2);
tree[rt].muit =1;
tree[rt].add= 0;
}

void build(int rt,int begin,int end)
{
tree[rt].add=0; tree[rt].muit=1;
for(int i=0;i<3;++i) tree[rt].sum[i]=0;
if(begin==end) return ;
int mid=(begin+end)>>1;
build(lson) ; build(rson);
}

void updata(int rt, int begin ,int end,int l,int r,int muil ,int add)
{
if(begin>=l&&r>=end)
{
cal(rt,muil,add,end-begin+1); return ;
}
pushdown(rt,end-begin+1);
int mid=(begin+end)>>1;
if(mid>=l) updata(lson,l,r,muil,add);
if(r>mid)  updata(rson,l,r,muil,add);
pushup(rt);
}

int query(int rt,int begin ,int end,int l,int r,int x)
{
if(begin>=l && r>=end)
{
return tree[rt].sum[x-1];
}
pushdown(rt,end-begin+1);
int ans=0;
int mid=(begin+end)>>1;
if(mid>=l) ans = (ans + query(lson,l,r,x) % mod)  %mod;
if(r>mid)  ans = (ans +query(rson ,l ,r ,x) %mod ) %mod;
return ans % mod;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
build(1,1,n);
while(m--)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
if(a==1) updata(1,1,n,b,c,1,d);
else if(a==2) updata(1,1,n,b,c,d,0);
else if(a==3) updata(1,1,n,b,c,0,d);
else printf("%d\n",query(1,1,n,b,c,d) % mod);
}
}
return 0;
}


HDU 4614
现在要你插花,有n个花瓶,m次操作,初始花瓶中无花,操作有两种方式

操作1:1 a b,从编号为a的花瓶开始插花,共插b朵花,花只能插到无花的花瓶中,如果最后插不完b朵花,剩下的花舍弃掉

操作2:1 a b,把从编号a到编号b的所有花瓶里的花全部清理掉

对于操作1,需要输出开始插花的瓶子编号,和最后插花的瓶子编号

对于操作2,需要输出在a~b中总共清理了多少个花瓶中的花

做法:线段树 1表示没有插花,0表示插了花
           对于操作二来说只用先查询区间和,再区间更改即可
           对于操作一来说,要二分两次找出左右两边的端点,进行区间更改
           (当时自己傻傻的写了一个单点更新,每次更新的时候先判断是否为1,然后与最大最小值比较,果断T)

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define lson rt<<1,begin,mid
#define rson rt<<1|1,mid+1,end
using namespace std;
const int maxn=50001+100;
int tree[maxn<<2];
int laze[maxn<<2];
void pushup(int rt)
{
tree[rt]=tree[rt<<1] + tree[rt<<1|1];
}
void pushdown(int rt,int k)
{
if(laze[rt]==1)
{
laze[rt<<1]=laze[rt<<1|1]=1;
tree[rt<<1]=k-k/2;
tree[rt<<1|1]=k/2;
laze[rt]=-1;
}
else if(laze[rt]==0)
{
laze[rt<<1|1]=laze[rt<<1]=0;
tree[rt<<1|1]=tree[rt<<1]=0;
laze[rt]=-1;
}
}

void build(int rt,int begin,int end)
{
tree[rt]=1; laze[rt]=-1;
if(begin==end) return;
int mid=(begin+end)>>1;
build(lson);
build(rson);
pushup(rt);
}

void updata(int rt, int begin,int end ,int l,int r,int x)
{
if(begin>=l&&r>=end)
{
laze[rt]=x;
tree[rt]=(end-begin+1)*x;
return;
}
pushdown(rt,end-begin+1);
int mid=(begin+end)>>1;
if(mid>=l) updata(lson,l,r,x);
if(r>mid)  updata(rson,l,r,x);
pushup(rt);
}

int query(int rt,int begin,int end,int l,int r)
{
if(begin>=l&& r>=end)
{
return tree[rt];
}
pushdown(rt,end-begin+1);
int ans=0;
int mid=(begin+end)>>1;
if(mid>=l) ans+=query(lson,l,r);
if(r>mid)  ans+=query(rson,l,r);
pushup(rt);
return ans;
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
build(1,1,n);
while(m--)
{
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==1)
{
++l;
int ans=query(1,1,n,l,n);
if(ans==0)
puts("Can not put any one.");
else
{
if(ans<r)  r=ans;
int ll=l,rr=n;
while(ll<=rr)
{
int mid=(ll+rr)>>1;
if(query(1,1,n,l,mid)>=1) rr=mid-1;
else  ll=mid+1;
}
int a=ll;
ll=l;rr=n;
while(ll<=rr)
{
int mid=(ll+rr)>>1;
if(query(1,1,n,l,mid)>=r) rr=mid-1;
else  ll=mid+1;
}
int b=ll;
updata(1,1,n,a,b,0);
printf("%d %d\n",a-1,b-1);
}
}
else
{
++r; ++l;
printf("%d\n",r-l+1-query(1,1,n,l,r));
updata(1,1,n,l,r,1);
}

}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: