您的位置:首页 > 其它

线段树单点更新+成段更新(好)hdu4973(多校联合)

2014-09-04 14:49 399 查看




Online Judge
Online Exercise
Online Teaching
Online Contests
Exercise Author

F.A.Q

Hand In Hand

Online Acmers

Forum | Discuss

Statistical Charts

Problem Archive

Realtime Judge Status

Authors Ranklist



C/C++/Java Exams

ACM Steps

Go to Job

Contest LiveCast

ICPC@China

Best Coder beta

VIP | STD
Contests

Virtual Contests

DIY | Web-DIY beta

Recent Contests



lee




Mail
0(0)



Control
Panel


Sign
Out


BestCoder官方QQ群:385386683 欢迎加入~
寻人启事:2014级新生看过来!

A simple simulation problem.

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 632 Accepted Submission(s): 246



Problem Description
There are n types of cells in the lab, numbered from 1 to n. These cells are put in a queue, the i-th cell belongs to type i. Each time I can use mitogen to double the cells in the interval [l, r]. For instance, the original
queue is {1 2 3 3 4 5}, after using a mitogen in the interval [2, 5] the queue will be {1 2 2 3 3 3 3 4 4 5}. After some operations this queue could become very long, and I can’t figure out maximum count of cells of same type. Could you help me?


Input
The first line contains a single integer t (1 <= t <= 20), the number of test cases.

For each case, the first line contains 2 integers (1 <= n,m<= 50000) indicating the number of cell types and the number of operations.

For the following m lines, each line represents an operation. There are only two kinds of operations: Q and D. And the format is:

“Q l r”, query the maximum number of cells of same type in the interval [l, r];

“D l r”, double the cells in the interval [l, r];

(0 <= r – l <= 10^8, 1 <= l, r <= the number of all the cells)


Output
For each case, output the case number as shown. Then for each query "Q l r", print the maximum number of cells of same type in the interval [l, r].

Take the sample output for more details.



Sample Input
1
5 5
D 5 5
Q 5 6
D 2 3
D 1 2
Q 1 7




Sample Output
Case #1:
2
3


题意:有两种操作,一种是把区间(l,r)内的每个数字复制,另一种是查询区间(l,r)区间内数量最多的数有多少个

思路:线段树,维护sum区间一共有多少个数,maxv区间最多的数有多少个,setv表示区间被复制了几次,这样当查询区间(l,r)首先得到其在原来的位置是多少,然后对于端点的值进行单点更新,中间的值进行成段更新就可以了。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=50010;
typedef long long LL;
int n,m;
struct IntervalTree
{
    LL sum[maxn<<2];
    LL maxv[maxn<<2];
    int setv[maxn<<2];
    void pushup(int o)
    {
        sum[o]=sum[o<<1]+sum[o<<1|1];
        maxv[o]=max(maxv[o<<1],maxv[o<<1|1]);
    }
    void build(int o,int l,int r)
    {
        setv[o]=0;
        if(l==r)
        {
            sum[o]=maxv[o]=1;
            return;
        }
        int mid=(l+r)>>1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        pushup(o);
    }
    int getID(int o,int l,int r,LL x)
    {
        if(l==r)return l;
        pushdown(o);
        int mid=(l+r)>>1;
        if(sum[o<<1]>=x)return getID(o<<1,l,mid,x);
        else return getID(o<<1|1,mid+1,r,x-sum[o<<1]);
    }
    void pushdown(int o)
    {
        if(setv[o])
        {
            setv[o<<1]+=setv[o];
            setv[o<<1|1]+=setv[o];
            sum[o<<1]<<=setv[o];
            maxv[o<<1]<<=setv[o];
            sum[o<<1|1]<<=setv[o];
            maxv[o<<1|1]<<=setv[o];
            setv[o]=0;
        }
    }
    void update1(int o,int l,int r,int x,LL val)
    {
        if(l==r)
        {
            sum[o]+=val;
            maxv[o]+=val;
            return;
        }
        pushdown(o);
        int mid=(l+r)>>1;
        if(x<=mid)update1(o<<1,l,mid,x,val);
        else update1(o<<1|1,mid+1,r,x,val);
        pushup(o);
    }
    void update2(int o,int l,int r,int q1,int q2)
    {
        if(q1<=l&&r<=q2)
        {
            setv[o]++;
            sum[o]*=2;
            maxv[o]*=2;
            return ;
        }
        pushdown(o);
        int mid=(l+r)>>1;
        if(q1<=mid)update2(o<<1,l,mid,q1,q2);
        if(q2>mid)update2(o<<1|1,mid+1,r,q1,q2);
        pushup(o);
    }
    LL querysum(int o,int l,int r,int q1,int q2)
    {
        if(q1<=l&&r<=q2)return sum[o];
        pushdown(o);
        int mid=(l+r)>>1;
        LL ans=0;
        if(q1<=mid)ans+=querysum(o<<1,l,mid,q1,q2);
        if(q2>mid)ans+=querysum(o<<1|1,mid+1,r,q1,q2);
        return ans;
    }
    LL query(int o,int l,int r ,int q1,int q2)
    {
        if(q1<=l&&r<=q2)return maxv[o];
        int mid=(l+r)>>1;
        pushdown(o);
        LL ans=0;
        if(q1<=mid)ans=max(ans,query(o<<1,l,mid,q1,q2));
        if(q2>mid)ans=max(ans,query(o<<1|1,mid+1,r,q1,q2));
        return ans;
    }
}tree;
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        tree.build(1,1,n);
        printf("Case #%d:\n",cas++);
        while(m--)
        {
            LL l,r;
            char op[5];
            scanf("%s%I64d%I64d",op,&l,&r);
            int id1=tree.getID(1,1,n,l);
            int id2=tree.getID(1,1,n,r);
            if(op[0]=='D')
            {
                if(id1==id2)
                {
                    LL x=r-l+1;
                    tree.update1(1,1,n,id1,x);
                }
                else//这里注意要先对右端点进行更新,因为如果先对左端点更新,右面的值会发生变化
                {
                    LL tmp=r-tree.querysum(1,1,n,1,id2-1);
                    tree.update1(1,1,n,id2,tmp);
                    tmp=tree.querysum(1,1,n,1,id1)-l+1;
                    tree.update1(1,1,n,id1,tmp);
                    int q1=id1+1,q2=id2-1;
                    if(q1<=q2)tree.update2(1,1,n,q1,q2);
                }
            }
            else
            {
                if(id1==id2)printf("%I64d\n",r-l+1);
                else
                {
                    LL ans=0;
                    LL tmp=r-tree.querysum(1,1,n,1,id2-1);
                    ans=max(ans,tmp);
                    tmp=tree.querysum(1,1,n,1,id1)-l+1;
                    ans=max(ans,tmp);
                    int q1=id1+1,q2=id2-1;
                    if(q1<=q2)ans=max(ans,tree.query(1,1,n,q1,q2));
                    printf("%I64d\n",ans);
                }
            }
        }
    }
    return 0;
}


还有更简洁的写法

update的时候在[L,R]这些数里找排在第[ql,qr]的,如果sum[o<<1]>=qr,就在左区间找[ql,qr],如果sum[p<<1]>ql就在右区间找[ql-sum[o<<1]],qr-sum[o<<1]],否则就在左边找[ql,sum[o<<1]],右区间找[1,qr-sum[o<<1]]。查询原理也一样。

#include<iostream>  
#include<algorithm>  
#include<queue>  
#include<cstdio>  
#include<cstdlib>  
#include<cmath>  
#include<cstring>  
#include<stack>  
#define INF 0x3f3f3f3f  
#define MAXN 50010  
#define MAXM 110  
#define MOD 1000000007  
#define MAXNODE 4*MAXN  
#define eps 1e-9  
using namespace std;  
typedef long long LL;  
LL T,N,M;  
char op[10];  
LL sum[MAXNODE],maxv[MAXNODE],mul[MAXNODE];  
void maintain(LL o){  
    sum[o]=sum[o<<1]+sum[o<<1|1];  
    maxv[o]=max(maxv[o<<1],maxv[o<<1|1]);  
}  
void build(LL o,LL L,LL R){  
    mul[o]=0;  
    if(L==R){  
        maxv[o]=sum[o]=1;  
        return;  
    }  
    LL mid=(L+R)>>1;  
    build(o<<1,L,mid);  
    build(o<<1|1,mid+1,R);  
    maintain(o);  
}  
void pushdown(LL o){  
    if(mul[o]){  
        LL lc=o<<1,rc=o<<1|1;  
        sum[lc]<<=mul[o];  
        sum[rc]<<=mul[o];  
        maxv[lc]<<=mul[o];  
        maxv[rc]<<=mul[o];  
        mul[lc]+=mul[o];  
        mul[rc]+=mul[o];  
        mul[o]=0;  
    }  
}  
void update(LL o,LL L,LL R,LL ql,LL qr){  
    if(L==R){  
        sum[o]+=qr-ql+1;  
        maxv[o]=sum[o];  
        return;  
    }  
    if(sum[o]==qr-ql+1){  
        mul[o]++;  
        sum[o]<<=1;  
        maxv[o]<<=1;  
        return;  
    }  
    pushdown(o);  
    LL mid=(L+R)>>1;  
    if(sum[o<<1]>=qr) update(o<<1,L,mid,ql,qr);  
    else if(sum[o<<1]<ql) update(o<<1|1,mid+1,R,ql-sum[o<<1],qr-sum[o<<1]);  
    else{  
        update(o<<1|1,mid+1,R,1,qr-sum[o<<1]);  
        update(o<<1,L,mid,ql,sum[o<<1]);  
    }  
    maintain(o);  
}  
LL query(LL o,LL L,LL R,LL ql,LL qr){  
    if(L==R) return qr-ql+1;  
    if(sum[o]==qr-ql+1) return maxv[o];  
    pushdown(o);  
    LL mid=(L+R)>>1;  
    if(sum[o<<1]>=qr) return query(o<<1,L,mid,ql,qr);  
    else if(sum[o<<1]<ql) return query(o<<1|1,mid+1,R,ql-sum[o<<1],qr-sum[o<<1]);  
    else return max(query(o<<1,L,mid,ql,sum[o<<1]),query(o<<1|1,mid+1,R,1,qr-sum[o<<1]));  
}  
int main(){  
    freopen("in.txt","r",stdin);  
    scanf("%I64d",&T);  
    LL cas=0;  
    while(T--){  
        printf("Case #%I64d:\n",++cas);  
        scanf("%I64d%I64d",&N,&M);  
        build(1,1,N);  
        while(M--){  
            LL ql,qr;  
            scanf("%s",op);  
            scanf("%I64d%I64d",&ql,&qr);  
            if(op[0]=='D') update(1,1,N,ql,qr);  
            else printf("%I64d\n",query(1,1,N,ql,qr));  
        }  
    }  
    return 0;  
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: