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

来源:互联网 发布:五线谱变简谱软件 编辑:程序博客网 时间:2024/06/06 01:28

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,endusing 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

题意:
  1. 一个公司里面每个员工都有一个顶头上司,一旦给某个员工分配任务后,这个员工以及该员工的所有下属都在做该任务。 
  2.     有若干操作,分配给员工任务以及查询该员工正在执行的任务。 
做法:首先线段树是很容易想到的,那关键是怎么在树上跑线段树,其实我们可以先用出入度找出树的根,然后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,endconst 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 ,endusing 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;    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,endusing 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;}













原创粉丝点击