kuangbin专题之线段树

啊。。这个专题才开的时候,学校就恢复了vj挂题的制度,加上各种比赛,以及文化课之类的,导致这个专题写的好慢。。。写完后也一直没时间总结博客。。就是懒…
-------------------------------------------------------------------------
感觉…自己越来越没有斗志了…天天像个废物一样,就只会写几个傻瓜题,比赛也是签个到就开始罚坐。。学个新的图论算法几乎要自闭,,
图论也太难了吧!!!
图论也太难了吧!!!
图论也太难了吧!!!
二分图写着写着就遇到了HK算法,然后看不懂,,只会套板子,写着写着觉得放到暑假集训再处理这个二分图吧,不如先去把次小生成树完善一下,,然后写了四个题就遇到了最小树形图。。。再次自闭。。。。
还是先把这个线段树专题总结一下吧
-------------------------------------------------------------------------
就三个题没补
一个是多重lazy标记。。写吐了。真不想写这个(不会。。
还有一个是扫描线处理周长问题(只学了处理面积,周长一时半会没看会。
最后一个就是很玄学的看都看不懂的题目。。说是三维线段树????
我太菜了…
-------------------------------------------------------------
开始正文
专题链接
A - 敌兵布阵 HDU - 1166
在这里插入图片描述
单点修改 区间查询
最简单的线段树操作了,不如放个树状数组上来吧

int lowbit(int x){return x&(-x);}
int arr[maxn];
void updata(int pos,int val,int n){
    while(pos<=n){
        arr[pos]+=val;
        pos+=lowbit(pos);
    }
}
int query(int pos){
    int ans=0;
    while(pos>0){
        ans+=arr[pos];
        pos-=lowbit(pos);
    }
    return ans;
}
int cas=0;
void solve(){
    ms(arr,0);
    int n;cin>>n;
    rep(i,1,n){
        int tmp;cin>>tmp;
        updata(i,tmp,n);
    }
    string ope;
    int a,b;
    cout<<"Case "<<++cas<<":"<<endl;
    while(cin>>ope&&ope[0]!='E'){
        cin>>a>>b;
        if(ope[0]=='A'){
            updata(a,b,n);
        }else if(ope[0]=='S'){
            updata(a,-b,n);
        }else{
            cout<<query(b)-query(a-1)<<endl;
        }
    }
}

B - I Hate It HDU - 1754
在这里插入图片描述
区间查询,单点更新
还是基本操作。。上题放树状数组,那这个就放线段树把

struct node{
    int l,r;
    int val;
}tree[maxn<<2];
void build(int rt,int l,int r){
    tree[rt].l=l;
    tree[rt].r=r;
    if(l==r){
        scanf("%d",&tree[rt].val);
        return ;
    }
    build(lson);
    build(rson);
    tree[rt].val=max(tree[ls].val,tree[rs].val);
}
void updata(int rt,int a,int b){
    int l=tree[rt].l,r=tree[rt].r;
    if(l==r&&r==a){
        tree[rt].val=b;
    }else{
        if(a<=md){
            updata(ls,a,b);
        }else{
            updata(rs,a,b);
        }
        tree[rt].val=max(tree[ls].val,tree[rs].val);
    }
}
int query(int rt,int a,int b){
    int l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b){
        return tree[rt].val;
    }else{
        if(b<=md){
            return query(ls,a,b);
        }else if(a>=md+1){
            return query(rs,a,b);
        }else{
            return max(query(ls,a,md),query(rs,md+1,b));
        }
    }
}
void solve(){
    int n,m;while(~scanf("%d %d",&n,&m)){
        build(1,1,n);
        while(m--){
            char str[30];int a,b;
            scanf("%s %d %d",str,&a,&b);
            if(str[0]=='Q'){
                cout<<query(1,a,b)<<endl;
            }else{
                updata(1,a,b);
            }
        }
    }
}

C - A Simple Problem with Integers POJ - 3468
在这里插入图片描述
嗯。。区间更新,区间查询
考察的是lazy标记的思想,单点修改必定会超时的
算是lazy标记入门题
我想不明白的是。。用scanf就一直wa…改成cin…就过了
迷惑。。。

struct node{
    ll l,r;
    ll val,tag;
}tree[maxn<<2];
void build(ll rt,ll l,ll r){
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].tag=0;
    if(l==r){
        cin>>tree[rt].val;
    }else{
        build(lson);
        build(rson);
        tree[rt].val=tree[ls].val+tree[rs].val;
    }
}
inline void push_down(ll rt){
    if(!tree[rt].tag){
        return ;
    }
    ll l=tree[rt].l,r=tree[rt].r;
    tree[ls].tag+=tree[rt].tag;
    tree[rs].tag+=tree[rt].tag;
    tree[ls].val+=(md-l+1)*tree[rt].tag;
    tree[rs].val+=(r-md)*tree[rt].tag;
    tree[rt].tag=0;
}
void updata(ll rt,ll a,ll b,ll c){
    ll l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b){
        tree[rt].tag+=c;
        tree[rt].val+=(r-l+1)*c;
        return ;
    }else{
        push_down(rt);
        if(b<=md){
            updata(ls,a,b,c);
        }else if(a>=md+1){
            updata(rs,a,b,c);
        }else{
            updata(ls,a,md,c);
            updata(rs,md+1,b,c);
        }
        tree[rt].val=tree[ls].val+tree[rs].val;
    }
}
ll query(ll rt,ll a,ll b){
    ll l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b){
        return tree[rt].val;
    }else{
        push_down(rt);
        if(b<=md){
            return query(ls,a,b);
        }else if(a>=md+1){
            return query(rs,a,b);
        }else{
            return query(ls,a,md)+query(rs,md+1,b);
        }
    }
}
void solve(){
    ll n,q;
    cin>>n>>q;
    build(1,1,n);
    while(q--){
        char ope[10];
        ll a,b,c;
        cin>>ope>>a>>b;
        if(ope[0]=='Q'){
            cout<<query(1,a,b)<<endl;
        }else{
            cin>>c;
            updata(1,a,b,c);
        }
    }
    
}

D - Mayor’s posters POJ - 2528
在这里插入图片描述
在这里插入图片描述
呃。线段树染色+离散化处理
数据太大了,需要离散化一下,不然无法建树
注意这里每一个点代表的是片段的颜色,比如3,4,5,6,7
4,6之间,3,4之间,6,7之间依次染了色,然后你离散化就成了,3,4,6,7,对应1,2,3,4,然后你记录出来的就是1,2有颜色,3,4有颜色,这就忽略了一种颜色!!,原本的应该是,3,4 ,,,5,,6,7
所以离散化的时候,对于每一个长度大于1的区间,就需要额外添加一个数进去来确保正确度!即

for(ll i=1;i<=sz-1;i++){
        if(v[i]-v[i-1]>1){
            v.pb(v[i-1]+1);
        }
    }

注意这个题染的是点,和下面那个题不同,这点要区分开
然后就没啥好说的了,上代码吧,注意线段树离散化的操作

struct node{
    ll l,r;
    ll val;
}tree[maxn<<4];
struct IUPUT{
    ll l,r;
}input[maxn];
ll vis[maxn<<4];
vector<ll>v;
ll ans=0;
void build(ll rt,ll l,ll r){
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].val=-1;
    if(l==r){
        return ;
    }
    build(lson);
    build(rson);
}
inline void push_down(ll rt){
    ll l=tree[rt].l,r=tree[rt].r;
    if(tree[rt].val!=-1&&l!=r){
        tree[ls].val=tree[rt].val;
        tree[rs].val=tree[rt].val;
        tree[rt].val=-1;
    }
}
void updata(ll rt,ll a,ll b,ll c){
    ll l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b){
        tree[rt].val=c;
        return ;
    }
    push_down(rt);
    if(b<=md){
        updata(ls,a,b,c);
    }else if(a>=md+1){
        updata(rs,a,b,c);
    }else{
        updata(ls,a,md,c);
        updata(rs,md+1,b,c);
    }
}
void query(ll rt,ll a,ll b){
    ll l=tree[rt].l,r=tree[rt].r;
    //de(tree[rt].val),de(l),de(r),de(a),de(b);
    if(l==a&&r==b&&tree[rt].val!=-1){
        ll tmp=tree[rt].val;
        if(!vis[tmp]){
            vis[tmp]=1;
            ans++;
        }
        return ;
    }
    if(tree[rt].val==-1&&l==r){
        return ;
    }
    push_down(rt);
    if(b<=md){
        query(ls,a,b);
    }else if(a>=md+1){
        query(rs,a,b);
    }else{
        query(ls,a,md);
        query(rs,md+1,b);
    }
}
void solve(){
    v.clear();
    ans=0;
    ll n=read();
    rep(i,1,n){
        input[i].l=read();
        input[i].r=read();
        v.pb(input[i].l);
        v.pb(input[i].r);
    }
    ll sz=v.size();
    sort(v.begin(),v.end());
    for(ll i=1;i<=sz-1;i++){
        if(v[i]-v[i-1]>1){
            v.pb(v[i-1]+1);
        }
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    sz=v.size();
    build(1,1,sz);
    rep(i,1,n){
        ll a=lower_bound(v.begin(),v.end(),input[i].l)-v.begin()+1;
        ll b=lower_bound(v.begin(),v.end(),input[i].r)-v.begin()+1;
        updata(1,a,b,i);
    }
    ms(vis,0);
    query(1,1,sz);
    cout<<ans<<endl;
}

E - Just a Hook HDU - 1698
在这里插入图片描述
在这里插入图片描述
就是个区间更新,区间查询的题目
题意:一个拐杖原本单位长度价值为1,然后每次选定一个 L L , R R 区间,把这个区间单位价值修改为 v a l val 最后求区间之和。。
就是lazy的应用吧

struct node{
    int l,r;
    int val,tag;
}tree[maxn<<2];
void build(int rt,int l,int r){
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].tag=0;
    if(l==r){
        tree[rt].val=1;
        return ;
    }
    build(lson);
    build(rson);
    tree[rt].val=tree[ls].val+tree[rs].val;
}
inline void push_down(int rt){
    int l=tree[rt].l,r=tree[rt].r;
    if(l==r||tree[rt].tag==0){
        tree[rt].tag=0;
        return ;
    }
    tree[ls].tag=tree[rs].tag=tree[rt].tag;
    tree[ls].val=(md-l+1)*tree[ls].tag;
    tree[rs].val=(r-md)*tree[rs].tag;
    tree[rt].tag=0;
}
void updata(int rt,int a,int b,int c){
    int l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b){
        tree[rt].tag=c;
        tree[rt].val=(r-l+1)*c;
        return ;
    }
    push_down(rt);
    if(b<=md){
        updata(ls,a,b,c);
    }else if(a>=md+1){
        updata(rs,a,b,c);
    }else{
        updata(ls,a,md,c);
        updata(rs,md+1,b,c);
    }
    tree[rt].val=tree[ls].val+tree[rs].val;
}
int query(int rt,int a,int b){
    int l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b){
        return tree[rt].val;
    }
    push_down(rt);
    if(b<=md){
        return query(ls,a,b);
    }else if(a>=md+1){
        return query(rs,a,b);
    }else{
        return query(ls,a,md)+query(rs,md+1,b);
    }
}
int cas=0;
void solve(){
    int n=read();build(1,1,n);
    int q=read();while(q--){
        int a=read(),b=read(),c=read();
        updata(1,a,b,c);
    }
    printf("Case %d: The total value of the hook is %d.\n",++cas,query(1,1,n));
}

F - Count the Colors ZOJ - 1610
在这里插入图片描述
在这里插入图片描述
也是线段树染色问题,每次把一个区域染成颜色 i i ,最后求出每种颜色有多少段,输出段数,为0(或者被覆盖完)则不用输出
因为这个染色的是线段,不是点,也即是说【1,2】 和【3,4】是不相邻的
这时候我们可以用 L L 来代替 L L L + 1 L+1 这个区间,更新数值的时候更新
L+1,R的点就可以了,最后暴力找出每个颜色的段数

struct segtree{
    int l,r;
    int val;
}tree[maxn<<2];
int vis[maxn],ans,cup[maxn];
void build(int rt,int l,int r){
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].val=-1;
    if(l==r){
        return ;
    }
    build(lson);
    build(rson);
}
inline void push_down(int rt){
    int l=tree[rt].l,r=tree[rt].r;
    if(l==r||tree[rt].val==-1){
        return ;
    }
    tree[ls].val=tree[rs].val=tree[rt].val;
    tree[rt].val=-1;
}
void updata(int rt,int a,int b,int c){
    //de(l),de(r);
    //de(rt);
    int l=tree[rt].l,r=tree[rt].r;
    //de(a),de(b),de(l),de(r);
    if(l==a&&r==b){
        tree[rt].val=c;
        return ;
    }
    push_down(rt);
    if(b<=md){
        updata(ls,a,b,c);
    }else if(a>=md+1){
        updata(rs,a,b,c);
    }else{
        updata(ls,a,md,c);
        updata(rs,md+1,b,c);
    }
    
}
void query(int rt,int a,int b){
    int l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b&&tree[rt].val!=-1){
        for(int i=l;i<=r;i++){
            cup[i]=tree[rt].val;
        }
        return ;
    }
    if(l==r&&tree[rt].val!=-1){
        return ;
    }
    push_down(rt);
    if(b<=md){
        query(ls,a,b);
    }else if(a>=md+1){
        query(rs,a,b);
    }else{
        query(ls,a,md);
        query(rs,md+1,b);
    }
    
}
void solve(){
    int n;while(~scanf("%d",&n)){
        int N=8001;
        build(1,1,N-1);
        ms(vis,0),ms(cup,-1);
        rep(i,1,n){
            int x1,x2,c;
            scanf("%d %d %d",&x1,&x2,&c);
            x1++;
            updata(1,x1,x2,c);
        }
        query(1,1,N-1);
        for(int i=1;i<=N;i++){
            if(cup[i-1]!=-1&&(i==1||cup[i-1]!=cup[i-2])){
                vis[cup[i-1]]++;
            }
        }
        for(int i=0;i<=N;i++){
            if(vis[i]){
                printf("%d %d\n",i,vis[i]);
            }
        }
        printf("\n");
    }
}

G - Balanced Lineup POJ - 3264
在这里插入图片描述
呃,区间最值查询,每次输出一个区间最大值与最小值的差值
简单题》。

struct segtree{
    int l,r;
    int mx,mn;
}tree[maxn<<2];
int ans1,ans2;
void build(int rt,int l,int r){
    tree[rt].l=l;
    tree[rt].r=r;
    if(l==r){
        int tmp=read();
        tree[rt].mx=tree[rt].mn=tmp;
        return ;
    }
    build(lson);
    build(rson);
    tree[rt].mx=max(tree[ls].mx,tree[rs].mx);
    tree[rt].mn=min(tree[ls].mn,tree[rs].mn);
}
void query(int rt,int a,int b){
    int l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b){
        ans1=max(ans1,tree[rt].mx);
        ans2=min(ans2,tree[rt].mn);
        return ;
    }
    if(b<=md){
        query(ls,a,b);
    }else if(a>=md+1){
        query(rs,a,b);
    }else{
        query(ls,a,md);
        query(rs,md+1,b);
    }
}
void solve(){
    int n=read(),q=read();
    build(1,1,n);
    while(q--){
        int a=read(),b=read();
        ans1=-1*INF;
        ans2=INF;
        query(1,a,b);
        printf("%d\n",ans1-ans2);
    }
}

H - Can you answer these queries? HDU - 4027
在这里插入图片描述
区间更新,区间求和
由于这个区间更新是开方操作。。。所以必然不能用lazy标记了。。
但是暴力会超时?那怎么办
仔细想想,开方操作对于一个整数来说,最多操作6,7次就变成1了,变成1之后的开方就不会再变化了,所以我们还是暴力更新。只不过需要维护一下每个区间是否全为1了,是的话就不需要更新了,区间求和就是常规套路了

struct segtree{
    ll l,r;
    ll val,be;
}tree[maxn<<2];
void build(int rt,int l,int r){
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].be=0;
    if(l==r){
        scanf("%lld",&tree[rt].val);
        if(tree[rt].val==1){
            tree[rt].be=1;
        }
        return ;
    }
    build(lson);
    build(rson);
    tree[rt].val=tree[ls].val+tree[rs].val;
    tree[rt].be= tree[rt].val==(r-l+1);
}
void updata(ll rt,ll a,ll b){
    ll l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b&&tree[rt].be==1){
        return ;
    }
    if(l==a&&l==r){
        tree[rt].val=sqrt(tree[rt].val);
    }else if(b<=md){
        updata(ls,a,b);
    }else if(a>=md+1){
        updata(rs,a,b);
    }else{
        updata(ls,a,md);
        updata(rs,md+1,b);
    }
    if(l != r){
        tree[rt].val=tree[ls].val+tree[rs].val;
    }
    tree[rt].be = tree[rt].val==(r-l+1);
}
ll query(ll rt,ll a,ll b){
    ll l=tree[rt].l,r=tree[rt].r;
    if(l==a&&r==b){
        return tree[rt].val;
    } else {
        if (b <= md) {
            return query(ls,a,b);
        } else if (a >= md+1){
            return query(rs,a,b);
        } else {
            return query(ls,a,md) + query(rs,md+1,b);
        }
    }
}
void solve(){
    ll cas=0;
    ll n;while(~scanf("%lld",&n)){
        build(1,1,n);
        ll m;scanf("%lld",&m);
        printf("Case #%lld:\n",++cas);
        while(m--){
            ll a,b,c;scanf("%lld %lld %lld",&a,&b,&c);
            if(b>c){
                swap(b,c);
            }
            if (a==0) {
                updata(1,b,c);
            } else {
                printf("%lld\n",query(1,b,c));
            }
        }
        puts("");
    }
}

先鸽了…明后天再继续补
——---------------------------------------------------~
I - Tunnel Warfare HDU - 1540
在这里插入图片描述
在这里插入图片描述
题意:每次可以破坏一个点,或者修复上一个被破坏的点,同时对于每次查询 p o s pos 位置,需要输出 p o s pos 可以和多少个村庄相连,
区间合并的题目,维护每个节点的 l x lx , m x mx , r x rx ,对于每次破坏操作,用一个栈维护,然后就是区间合并的基本操作了
注意 p u s h u p push up 函数的书写,这点是主要的

inline void push_up(int rt){
    int l=tree[rt].l,r=tree[rt].r;
    if(l == r){
        return ;
    }
    tree[rt].lx=tree[ls].lx;
    tree[rt].rx=tree[rs].rx;
    tree[rt].mx = max(max(tree[ls].mx,tree[rs].mx),tree[ls].rx+tree[rs].lx);
    if(tree[ls].lx == tree[ls].r - tree[ls].l + 1){
        tree[rt].lx += tree[rs].lx;
    }
    if(tree[rs].rx == tree[rs].r - tree[rs].l + 1){
        tree[rt].rx += tree[ls].rx;
    }
}

如果左儿子的lx等于左区间长度,那么这个节点lx就可以延伸到右边了
同时还有查询操作的写法,注意分段处理联通情况

struct segtree{
    int l,r;
    int lx,rx,mx;
}tree[maxn<<2];
void build(int rt,int l,int r){
    tree[rt]={l,r,r-l+1,r-l+1,r-l+1};
    if(l == r){
        return ;
    } else {
        build(lson);
        build(rson);
    }
}
inline void push_up(int rt){
    int l=tree[rt].l,r=tree[rt].r;
    if(l == r){
        return ;
    }
    tree[rt].lx=tree[ls].lx;
    tree[rt].rx=tree[rs].rx;
    tree[rt].mx = max(max(tree[ls].mx,tree[rs].mx),tree[ls].rx+tree[rs].lx);
    if(tree[ls].lx == tree[ls].r - tree[ls].l + 1){
        tree[rt].lx += tree[rs].lx;
    }
    if(tree[rs].rx == tree[rs].r - tree[rs].l + 1){
        tree[rt].rx += tree[ls].rx;
    }
}
void updata(int rt,int pos,int f){
    int l=tree[rt].l,r=tree[rt].r;
    if(l==r&&l==pos){
        tree[rt]={l,r,f,f,f};
        return ;
    } else {
        if(pos <= md){
            updata(ls,pos,f);
        }else {
            updata(rs,pos,f);
        }
        push_up(rt);
    }
}
int query(int rt,int pos){
    int l=tree[rt].l,r=tree[rt].r;
    if(l == r || tree[rt].mx == 0 || tree[rt].mx == r-l+1){
        return tree[rt].mx;
    }
    if(pos <= md){
        if(pos < md-tree[ls].rx+1 ){
            return query(ls,pos);
        } else {
            return query(ls,pos) + query(rs,md+1);
        }
    } else {
        if (pos > md+1+tree[rs].lx-1){
            return query(rs,pos);
        } else {
            return query(rs,pos)+query(ls,md);
        }
    }
}
void solve(){
    int n,m;while(~scanf("%d %d",&n,&m)){
    _stack sta;
    char str[10];
    build(1,1,n);
    int pos;

    while(m--){
        scanf("%s",str);
        if(str[0]=='D'){
            scanf("%d",&pos);
            updata(1,pos,0);
            sta.push(pos);
        }else if(str[0]=='Q'){
            scanf("%d",&pos);
            int ans=query(1,pos);
            printf("%d\n",ans);
        }else{
            if(!sta.empty()){
                pos = sta.top();
                sta.pop();
                updata(1,pos,1);
            }
        }
    }
    }
}

J - Assign the task HDU - 3974
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
好题!
用dfs序来建树,根据关系,我们可以统计每个数的入度,找出入度为0的数(此题唯一),然后用一个in和out数组进行dfs开始建树,对于每个数而言
in和out就是这个数所管理的范围,dfs的过程,就可以把数之间关系用In,out来维护好了

int in[maxn],out[maxn],root[maxn];
vector<int>G[maxn];
struct segtree {
    int l,r;
    int tag,val;
}tree[maxn<<2];
void dfs(int now,int &time){
    time++;
    in[now]=time;
    int sz=G[now].size();
    rep(i,0,sz-1){
        dfs(G[now][i],time);
    }
    time++;
    out[now]=time;
}
void build(int rt,int l,int r){
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].tag=-1;
    tree[rt].val=-1;
    if(l == r){
        return ;
    }
    build(lson);
    build(rson);
}
inline void push_down(int rt){
    int l=tree[rt].l,r=tree[rt].r;
    if(l == r || tree[rt].tag == -1){
        return ;
    } else {
        tree[ls].tag = tree[rs].tag = tree[rt].tag;
        tree[ls].val = tree[rs].val = tree[rt].val;
        tree[rt].tag = -1; 
    }
}
void updata (int rt,int a,int b,int f){
    int l=tree[rt].l,r=tree[rt].r;
    if(l == a && r== b){
        tree[rt].val = f;
        tree[rt].tag = f;
        return ;
    }
    push_down(rt);
    if (b <= md){
        updata(ls,a,b,f);
    } else if(a >= md+1){
        updata(rs,a,b,f);
    } else {
        updata(ls,a,md,f);
        updata(rs,md+1,b,f);
    }
}
int query(int rt,int pos){
    int l=tree[rt].l,r=tree[rt].r;
    if(l == r && l == pos){
        return tree[rt].val;
    } else {
        push_down(rt);
        if( pos <= md){
            return query(ls,pos);
        } else {
            return query(rs,pos);
        }
    }
}
int cas=0;
void solve(){
    ms(in,0),ms(out,0),ms(root,0);
    int n;cin>>n;
    rep(i,1,n){
        G[i].clear();
    }
    rep(i,1,n-1){
        int u,v;
        cin>>u>>v;
        G[v].pb(u);
        root[u]++;
    }
    int time=0;
    rep(i,1,n){
        if(root[i]==0){
            dfs(i,time);
            break;
        }
    }

    n<<=1;
    build(1,1,n);
    cout<<"Case #"<<++cas<<":\n";

    int m;cin>>m;
    while(m--){
        char ope[10];
        int a,b;
        cin>>ope;
        //de(ope);
        if(ope[0]=='C'){
            cin>>a;
            int ans=query(1,in[a]);
            cout<<ans<<'\n';
        }else {
            cin>>a>>b;
            updata(1,in[a],out[a],b);
        }
        //getchar();
    }
}

K题鸽了
L - Vases and Flowers HDU - 4614
在这里插入图片描述
在这里插入图片描述
插花,其实就是区间更新,对于每次插花的请求,找出当前这个区间能插花的数目,小于1就输出不可,反之则插满,每次插花二分查找出起点和终点,然后更新数值,lazy的基本功就不说了,清理花就是先查找出共有多少花,然后全部清空就好了

struct segtree {
    int l,r;
    int val,tag;
} tree[maxn<<2];
void build(int rt, int l, int r) {
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].tag = -1;
    if (l == r) {
        tree[rt].val = 1;
    } else {
        build(lson);
        build(rson);
        tree[rt].val = tree[ls].val + tree[rs].val;
    }
}
inline void push_down (int rt) {
    int l = tree[rt].l, r = tree[rt].r;
    if (l == r || tree[rt].tag == -1) {
        return ;
    } else {
        int tmp = tree[rt].tag;
        tree[ls].tag = tmp;
        tree[rs].tag = tmp;
        tree[ls].val = (md - l + 1)*tmp;
        tree[rs].val = (r - md)*tmp;
        tree[rt].tag = -1;
    }
}
void updata(int rt, int a, int b, int c) {
    int l = tree[rt].l, r = tree[rt].r;
    if(l == a && r == b){
        tree[rt].val = (r - l + 1)*c;
        tree[rt].tag = c;
        return ;
    }
    push_down(rt);
    if (b <= md) {
        updata(ls, a, b, c);
    } else if (a >= md+1) {
        updata(rs, a, b, c);
    } else {
        updata(ls, a, md, c);
        updata(rs, md+1, b, c);
    }
    tree[rt].val = tree[ls].val + tree[rs].val;
}
int query (int rt, int a, int b) {
    int l = tree[rt].l ,r = tree[rt].r ;
    if ( l == a && r == b) {
        return tree[rt].val;
    } else {
        push_down(rt);
        if ( b <= md) {
            return query( ls, a, b);
        } else if ( a >= md+1){
            return query( rs, a, b);
        } else {
            return query( ls, a, md) + query( rs, md+1, b);
        }
    }
}
int cas = 0;
void solve() {
    int n,m;scanf("%d %d",&n, &m);
    build( 1, 1, n);
    while (m--) {
        int a,b,ope;
        scanf("%d %d %d",&ope, &a, &b);
        if ( ope == 1) {
            a++;
            int num = query(1, a, n);
            if (num == 0) {
                puts("Can not put any one.");
            } else {
                num = min(num, b);
                int st = a, ed = n;
                //left
                int L = a, R = n;
                while ( L <= R) {
                    int mid = L + R >> 1;
                    int tmp = query(1, a, mid);
                    if ( tmp >= 1) {
                        st = mid;
                        R = mid - 1;
                    } else {
                        L = mid + 1;
                    }
                }

                // right
                L = a,R = n;
                while (L <= R) {
                    int mid = L + R >> 1;
                    int tmp = query(1, a, mid);
                    if ( tmp >= num) {
                        ed = mid;
                        R = mid - 1;
                    } else {
                        L = mid + 1;
                    }
                }

                printf ("%d %d\n",st-1,ed-1);
                updata (1, st, ed, 0);
            }
        } else {
            a++,b++;
            int num = query ( 1, a, b);
            printf("%d\n",b-a+1-num);
            updata (1,a,b,1);
        }
    }
    puts("");
}

M - 约会安排 HDU - 4553
在这里插入图片描述
在这里插入图片描述
区间合并
维护两个区间,屌丝只更新屌丝,女神同时更新两个
每次查询,优先查询屌丝,然后是女神
注意pushup函数的书写就好了

struct segtree {
    int l,r;
    int lx,mx,rx;
    int tag;
}tree[maxn<<2][2];
inline void push_down(int rt){
    for(int i=0;i<=1;i++){
        int l=tree[rt][i].l,r=tree[rt][i].r;
        if(tree[rt][i].tag==-1){
            continue ;
        }
        int tmp=tree[rt][i].tag;
        tree[ls][i].lx=tree[ls][i].rx=tree[ls][i].mx=tmp*(tree[ls][i].r-tree[ls][i].l+1);
        tree[rs][i].lx=tree[rs][i].rx=tree[rs][i].mx=tmp*(tree[rs][i].r-tree[rs][i].l+1);
        tree[ls][i].tag=tree[rs][i].tag=tree[rt][i].tag;
        tree[rt][i].tag=-1;
    }
}
inline void push_up(int rt){
    for(int i=0;i<=1;i++){
        int l=tree[rt][i].l,r=tree[rt][i].r;
        //if(l==r){
            //continue;
        //} else {
            tree[rt][i].lx=tree[ls][i].lx;
            tree[rt][i].rx=tree[rs][i].rx;
            tree[rt][i].mx=max(max(tree[ls][i].mx,tree[rs][i].mx),tree[ls][i].rx+tree[rs][i].lx);
            if(tree[rt][i].lx==tree[ls][i].r-tree[ls][i].l+1){
                tree[rt][i].lx+=tree[rs][i].lx;
            }
            if(tree[rt][i].rx==tree[rs][i].r-tree[rs][i].l+1){
                tree[rt][i].rx+=tree[ls][i].rx;
            }
       // }
    }
}
void build(int rt,int l,int r){
    for(int i=0;i<=1;i++){
        tree[rt][i].l=l;
        tree[rt][i].r=r;
        tree[rt][i].lx=tree[rt][i].rx=tree[rt][i].mx=r-l+1;
        tree[rt][i].tag=-1;
    }
    if(l==r){
        return ;
    }
    build(lson);
    build(rson);
}
void updata(int rt,int pos,int a,int b,int f){
    int l=tree[rt][pos].l;
    int r=tree[rt][pos].r;
    if(l==a&&r==b){
        tree[rt][pos].tag=f;
        tree[rt][pos].lx=tree[rt][pos].rx=tree[rt][pos].mx=(r-l+1)*f;
        return ;
    }
    push_down(rt);
    if(b<=md){
        updata(ls,pos,a,b,f);
    }else if(a>=md+1){
        updata(rs,pos,a,b,f);
    }else {
        updata(ls,pos,a,md,f);
        updata(rs,pos,md+1,b,f);
    }
    push_up(rt);
}
int query(int rt,int pos,int len){
    int l=tree[rt][pos].l,r=tree[rt][pos].r;
    if(l==r){
        return l;
    }
    push_down(rt);
    if(tree[ls][pos].mx>=len){
        return query(ls,pos,len);
    }else if(tree[ls][pos].rx>=len-tree[rs][pos].lx){
        return tree[ls][pos].r-tree[ls][pos].rx+1;
    }else {
        return query(rs,pos,len);
    }
}
int cas=0;
void solve(){
    char ope[10];
    int T,N;
    scanf("%d %d",&T,&N);
    build(1,1,T);
    printf("Case %d:\n",++cas);
    while(N--){
        int pos;
        scanf("%s",ope);
        //de(ope);
        if(ope[0]=='D'){
            int tot;scanf("%d",&tot);
            if(tree[1][0].mx<tot){
                puts("fly with yourself");
            }else{
                pos=query(1,0,tot);
                printf("%d,let's fly\n",pos);
                updata(1,0,pos,pos+tot-1,0);
            }
        }else if(ope[0]=='N'){
            int tot;scanf("%d",&tot);
            if(tree[1][0].mx<tot&&tree[1][1].mx<tot){
                puts("wait for me");
            }else{
                if(tree[1][0].mx>=tot){
                    pos=query(1,0,tot);
                }else{
                    pos=query(1,1,tot);
                }
                printf("%d,don't put my gezi\n",pos);
                updata(1,0,pos,pos+tot-1,0);
                updata(1,1,pos,pos+tot-1,0);
            }
        }else{
            int a,b;scanf("%d %d",&a,&b);
            updata(1,0,a,b,1);
            updata(1,1,a,b,1);
            puts("I am the hope of chinese chengxuyuan!!");
        }
    }
}

N题还不会,鸽了
O - 覆盖的面积 HDU - 1255
在这里插入图片描述
扫描线模板题,注意这个题要求的是覆盖超过两次的面积,所以需要注意更新len的写法,下面那个题更为简单点

struct LINE {
    double x1,x2,h;
    int mark;
    bool operator < (const LINE &b)const{
        return h<b.h;
    }
}line[maxn];
struct segtree {
    int l,r;
    int be;
    double len1,len2;
}tree[maxn<<2];
double X[maxn];
void build(int rt,int l,int r){
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].be=0;
    tree[rt].len1=tree[rt].len2=0.0;
    if(l==r){
        return ;
    } else {
        build(lson);
        build(rson);
    }
}
inline void push_up(int rt){
    int l=tree[rt].l,r=tree[rt].r;
    if(tree[rt].be){
        tree[rt].len1=X[r+1]-X[l];
    } else if(l==r){
        tree[rt].len1=0;
    }else{
        tree[rt].len1=tree[ls].len1+tree[rs].len1;
    }

    if(tree[rt].be>1){
        tree[rt].len2=X[r+1]-X[l];
    }else if(tree[rt].be==1){
        if(l==r){
            tree[rt].len2 = 0;
        } else {
            tree[rt].len2=tree[ls].len1+tree[rs].len1;
        }
    }else{
        if(l == r){
            tree[rt].len2 = 0;
        } else {
            tree[rt].len2 = tree[ls].len2 + tree[rs].len2;
        }
    }
}
void updata(int rt,const double L,const double R,int f){
    int l=tree[rt].l,r=tree[rt].r;
    if(X[l]>=R||X[r+1]<=L){
        return ;
    }
    if(X[l]>=L&&X[r+1]<=R){
        tree[rt].be+=f;
        push_up(rt);
        return ;
    }
   // if(X[l]<=X[md+1]){
        updata(ls,L,R,f);
    //}
    //if(X[r]>=X[md+1]){
        updata(rs,L,R,f);
    //}
    push_up(rt);
}
void solve(){
    int n;scanf("%d",&n);
    rep(i,1,n){
        double xx1,xx2,yy1,yy2;
        scanf("%lf %lf %lf %lf",&xx1,&yy1,&xx2,&yy2);
        line[i*2-1]={xx1,xx2,yy1,1};
        line[i*2]={xx1,xx2,yy2,-1};
        X[i*2]=xx1;
        X[i*2-1]=xx2;
    }
    n<<=1;
    sort(X+1,X+n+1);
    sort(line+1,line+n+1);
    int tot = unique(X+1,X+n+1)-X-1;
    build(1,1,tot-1);

    double ans=0;
    rep(i,1,n-1){
        updata(1,line[i].x1,line[i].x2,line[i].mark);
        ans+=tree[1].len2*(line[i+1].h-line[i].h);
    }
    printf("%.2f\n",ans);
}

P - Atlantis HDU - 1542
在这里插入图片描述
给出每块岛覆盖的地方,求问最后的总面积
这个没啥说的了,就是一个扫描线,(说是二维线段树,按我觉得还是一维的,只维护了线段的长度而已`

struct scanline {
    double x1,x2;
    double h;
    int tag;
    bool operator < (const scanline &b) const {
        return h < b.h;
    }
}arr[maxn];
struct segtree {
    int l,r;
    double len;
    int tag;
}tree[maxn];
double X[maxn];
void build(int rt,int l,int r) {
    //de(rt),de(l),de(r);
    tree[rt].l = l;
    tree[rt].r = r;
    tree[rt].tag = 0;
    tree[rt].len=0.0;
    if(l == r){
        return ;
    } else {
        build (lson);
        build (rson);
    }
}
inline void push_up(int rt) {
    int l = tree[rt].l, r = tree[rt].r;
    if(tree[rt].tag){
        tree[rt].len=X[r+1]-X[l];
    } else {
        if(l == r) {
            tree[rt].len=0.0;
        } else {
            tree[rt].len = tree[ls].len + tree[rs].len;
        }
    }
}
void updata (int rt,double a,double b,int mark) {
    int l = tree[rt].l, r = tree[rt].r;
    if(X[r+1] <= a || X[l] >= b){
        return ;
    }
    if(X[l] >= a && X[r+1] <= b){
        tree[rt].tag+=mark;
        push_up(rt);
        return ;
    }
    updata(ls,a,b,mark);
    updata(rs,a,b,mark);
    push_up(rt);
}
int cas = 0;
void solve() {
    int n;while(~scanf("%d",&n)&&n) {
        rep (i, 1, n) {
            double xx1,xx2,yy1,yy2;
            scanf("%lf %lf %lf %lf",&xx1,&yy1,&xx2,&yy2);
            arr[i*2-1] = scanline {xx1, xx2, yy1, 1};
            arr[i*2] = scanline {xx1, xx2, yy2, -1};
            X[i*2] = xx1;
            X[i*2-1] = xx2;
        }
        n <<= 1;

        sort(arr+1,arr+n+1);
        sort(X+1,X+n+1);
        int cnt = unique(X+1,X+n+1)-X-1;
        //de(cnt);
        build(1,1,cnt-1);
        double ans=0.0;
        rep(i,1,n-1){
            updata(1,arr[i].x1,arr[i].x2,arr[i].tag);
            ans+=tree[1].len*(arr[i+1].h-arr[i].h);
        }
        printf("Test case #%d\n",++cas);
        printf("Total explored area: %.2f\n\n",ans); 
    }
}

最后一题不会嘿嘿完结了

猜你喜欢

转载自blog.csdn.net/leoxe/article/details/106291234
今日推荐