zoukankan      html  css  js  c++  java
  • 【日记】12.3

    12.3日记

    线段树

    染色问题困扰好久……

    1. 洛谷P2161。安排约定问题。

    思路:这道题其实应该是用平衡树的。不过如果涉及到平衡树,那么就考虑能不能直接套用set。既然有只保留一个的特性,那么就可以利用set只保留一个的特性,让冲突的设计重载运算符<让其相等,即可进行去重。由于每个元素只会进出一次,因此复杂度是正确的。

    注意:重载set运算符要这么干:

    struct Date{
        int l,r;
        Date(int a=0,int b=0):l(a),r(b){}
        bool operator<(const Date &x)const{
            return r<x.l;
        }
    };
    set<Date> st;
    

    多加const。

    染色解法感觉太麻烦了。

    //插入区间并删除冲突+询问区间个数
    #include<bits/stdc++.h>
    using namespace std;
    struct Date{
        int l,r;
        Date(int a=0,int b=0):l(a),r(b){}
        bool operator<(const Date &x)const{
            return r<x.l;
        }
    };
    set<Date> st;
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            char s[3];
            scanf("%s",s);
            if (s[0]=='B')
                printf("%d
    ",st.size());
            else{
                int l,r,last=st.size();
                scanf("%d%d",&l,&r);
                set<Date>::iterator it=st.find(Date(l,r));
                while(it!=st.end())
                    st.erase(it),it=st.find(Date(l,r));
                printf("%d
    ",last-st.size());
                st.insert(Date(l,r));
            }
        }
        return 0;
    }
    
    
    1. POJ2777,HDU5023。线段树染色问题。

    功能:区间修改+区间查询不同数个数。不同颜色个数较少。

    构造:状压每个颜色。v[id]表示当前区间所有颜色(状压)。维护区间值的|值。用lazy减少修改次数保证单次logn。

    注意:多组数据清空啊……

    POJ2777:

    //区间修改+区间不同数个数(少)
    #include<cstdio>
    #include<algorithm>
    #define mid (l+r)/2
    using namespace std;
    const int M=1e5+20;
    int v[4*M],lazy[4*M];
    inline void push_up(int id){
        v[id]=v[id*2]|v[id*2+1];
    }
    inline void push_down(int id){
        if (lazy[id])
            lazy[id*2]=lazy[id*2+1]=v[id*2]=v[id*2+1]=lazy[id],
            lazy[id]=0;
    }
    void build(int id,int l,int r){
        if (l==r){
            v[id]=2;
            return;
        }
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        push_up(id);
    }
    void operate(int id,int l,int r,int ql,int qr,int x){
        if (ql<=l&&r<=qr){
            v[id]=lazy[id]=x;
            return;
        }
        push_down(id);
        if (ql<=mid)
            operate(id*2,l,mid,ql,qr,x);
        if (mid<qr)
            operate(id*2+1,mid+1,r,ql,qr,x);
        push_up(id);
    }
    int query(int id,int l,int r,int ql,int qr){
        if (ql<=l&&r<=qr)
            return v[id];
        push_down(id);
        int sum=0;
        if (ql<=mid)
            sum|=query(id*2,l,mid,ql,qr);
        if (mid<qr)
            sum|=query(id*2+1,mid+1,r,ql,qr);
        return sum;
    }
    int main(){
        int l,t,o;
        scanf("%d%d%d",&l,&t,&o);
        build(1,1,l);
        for(int i=1;i<=o;++i){
            char s[2];
            int a,b,c;
            scanf("%s",s);
            if (s[0]=='C'){
                scanf("%d%d%d",&a,&b,&c);
                operate(1,1,l,min(a,b),max(a,b),1<<c);
            }
            else{
                scanf("%d%d",&a,&b);
                int ca=query(1,1,l,min(a,b),max(a,b)),ans=0;
                while(ca)
                    ans+=(ca&1),ca>>=1;
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    

    HDU5023:

    //线段树染色升级版
    #include<bits/stdc++.h>
    #define mid (l+r)/2
    using namespace std;
    const int M=1e6+20;
    int v[4*M],lazy[4*M];
    inline void push_up(int id){
        v[id]=v[id*2]|v[id*2+1];
    }
    inline void push_down(int id){
        if (lazy[id])
            lazy[id*2]=lazy[id*2+1]=v[id*2]=v[id*2+1]=lazy[id],
            lazy[id]=0;
    }
    void build(int id,int l,int r){
    	lazy[id]=0;
        if (l==r){
            v[id]=(1<<2);
            return;
        }
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        push_up(id);
    }
    void operate(int id,int l,int r,int ql,int qr,int x){
        if (ql<=l&&r<=qr){
            v[id]=lazy[id]=x;
            return;
        }
        push_down(id);
        if (ql<=mid)
            operate(id*2,l,mid,ql,qr,x);
        if (mid<qr)
            operate(id*2+1,mid+1,r,ql,qr,x);
        push_up(id);
    }
    int query(int id,int l,int r,int ql,int qr){
        if (ql<=l&&r<=qr)
            return v[id];
        push_down(id);
        int sum=0;
        if (ql<=mid)
            sum|=query(id*2,l,mid,ql,qr);
        if (mid<qr)
            sum|=query(id*2+1,mid+1,r,ql,qr);
        return sum;
    }
    int main(){
        int l,o;
        while(~scanf("%d%d",&l,&o)){
        	if (l==0&&o==0)
        		break;
    	    build(1,1,l);
    	    for(int i=1;i<=o;++i){
    	        char s[2];
    	        int a,b,c;
    	        scanf("%s",s);
    	        if (s[0]=='P'){
    	            scanf("%d%d%d",&a,&b,&c);
    	            operate(1,1,l,a,b,1<<c);
    	        }
    	        else{
    	            scanf("%d%d",&a,&b);
    	            int ca=query(1,1,l,a,b);
    	            vector<int> v;
    	            for(int j=1;j<=30;++j)
    	                if((1<<j)&ca)
    	                    v.push_back(j);
    	            printf("%d",v[0]);
    	            for(int j=1;j<v.size();++j)
    	                printf(" %d",v[j]);
    	            putchar('
    ');
    	        }
    	    }
    	}
        return 0;
    }
    
    
    1. HDU1166。单点加减+区间求和。

    比较简单,写的很快。

    //单点加减+区间求和
    #include<bits/stdc++.h>
    #define mid (l+r)/2
    using namespace std;
    const int M=5e4+20;
    int v[4*M],a[M];
    inline void push_up(int id){
        v[id]=v[id*2]+v[id*2+1];
    }
    void build(int id,int l,int r){
        if (l==r){
            v[id]=a[l];
            return;
        }
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        push_up(id);
    }
    void operate(int id,int l,int r,int pos,int x){
        if (l==r){
            v[id]+=x;
            return;
        }
        if (pos<=mid)
            operate(id*2,l,mid,pos,x);
        else
            operate(id*2+1,mid+1,r,pos,x);
        push_up(id);
    }
    int query(int id,int l,int r,int ql,int qr){
        if (ql<=l&&r<=qr)
            return v[id];
        int ans=0;
        if (ql<=mid)
            ans+=query(id*2,l,mid,ql,qr);
        if (mid<qr)
            ans+=query(id*2+1,mid+1,r,ql,qr);
        return ans;
    }
    int main(){
        int T;
        scanf("%d",&T);
        for(int z=1;z<=T;++z){
            printf("Case %d:
    ",z);
            int n;
            scanf("%d",&n);
            for(int i=1;i<=n;++i)
                scanf("%d",&a[i]);
            build(1,1,n);
            char s[10];
            scanf("%s",s);
            while(s[0]!='E'){
                int b,c;
                scanf("%d%d",&b,&c);
                if (s[0]=='Q')
                    printf("%d
    ",query(1,1,n,b,c));
                else if (s[0]=='A')
                    operate(1,1,n,b,c);
                else if (s[0]=='S')
                    operate(1,1,n,b,-c);
                scanf("%s",s);
            }
        }
        return 0;
    }
    
    1. HDU1754。单点修改+区间查询最大值
    //单点修改+区间最大值
    #include<bits/stdc++.h>
    #define mid (l+r)/2
    using namespace std;
    const int M=2e5+20;
    int v[4*M],a[M];
    inline void push_up(int id){
        v[id]=max(v[id*2],v[id*2+1]);
    }
    void build(int id,int l,int r){
        if (l==r){
            v[id]=a[l];
            return;
        }
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        push_up(id);
    }
    void operate(int id,int l,int r,int pos,int x){
        if (l==r){
            v[id]=x;
            return;
        }
        if (pos<=mid)
            operate(id*2,l,mid,pos,x);
        else
            operate(id*2+1,mid+1,r,pos,x);
        push_up(id);
    }
    int query(int id,int l,int r,int ql,int qr){
        if (ql<=l&&r<=qr)
            return v[id];
        int ans=0;
        if (ql<=mid)
            ans=max(ans,query(id*2,l,mid,ql,qr));
        if (mid<qr)
            ans=max(ans,query(id*2+1,mid+1,r,ql,qr));
        return ans;
    }
    int main(){
        int n,m;
        while(~scanf("%d%d",&n,&m)){
            for(int i=1;i<=n;++i)
                scanf("%d",&a[i]);
            build(1,1,n);
            for(int i=1;i<=m;++i){
                char s[3];
                scanf("%s",s);
                int a,b;
                scanf("%d%d",&a,&b);
                if (s[0]=='Q')
                    printf("%d
    ",query(1,1,n,a,b));
                else
                    operate(1,1,n,a,b);
            }
        }
        return 0;
    }
    
    1. HDU1698。区间修改+区间求和。

    一个是注意清空,另外一个是pushdown操作,下方的时候要乘区间长度。以后还是按照大佬的那套吧,确实会更方便一些。

    //区间修改+区间和
    #include<bits/stdc++.h>
    #define mid (l+r)/2
    using namespace std;
    const int M=1e5+20;
    int v[4*M],lazy[4*M];
    inline void pushup(int id){
        v[id]=v[id*2]+v[id*2+1];
    }
    inline void pushdown(int id,int l,int r){
        if (lazy[id])
            lazy[id*2]=lazy[id*2+1]=lazy[id],
            v[id*2]=lazy[id]*(mid-l+1),
            v[id*2+1]=lazy[id]*(r-mid),
            lazy[id]=0;
    }
    void build(int id,int l,int r){
        lazy[id]=0;
        if (l==r){
            v[id]=1;
            return;
        }
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        pushup(id);
    }
    void operate(int id,int l,int r,int ql,int qr,int x){
        if (ql<=l&&r<=qr){
            v[id]=x*(r-l+1),lazy[id]=x;
            return;
        }
        pushdown(id,l,r);
        if (ql<=mid)
            operate(id*2,l,mid,ql,qr,x);
        if (mid<qr)
            operate(id*2+1,mid+1,r,ql,qr,x);
        pushup(id);
    }
    int query(int id,int l,int r,int ql,int qr){
        if (ql<=l&&r<=qr)
            return v[id];
        pushdown(id,l,r);
        int sum=0;
        if (ql<=mid)
            sum+=query(id*2,l,mid,ql,qr);
        if (mid<qr)
            sum+=query(id*2+1,mid+1,r,ql,qr);
        return sum;
    }
    int main(){
        int T;
        scanf("%d",&T);
        for(int z=1;z<=T;++z){
            int n,q;
            scanf("%d%d",&n,&q);
            build(1,1,n);
            for(int i=1;i<=q;++i){
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                operate(1,1,n,a,b,c);
            }
            printf("Case %d: The total value of the hook is %d.
    ",z,query(1,1,n,1,n));
        }
        return 0;
    }
    
    1. OpenJ2299。n个不同数组成的数列,问有多少个逆序对。

    模板:一维偏序。可以归并,也可以树状数组。首先离散化,之后从后往前,将a[i]置为1,将1-i-1的区间和加入答案即可。注意开LL!

    //单点修改+区间查询和
    #include<bits/stdc++.h>
    using namespace std;
    const int M=5e5+20;
    int num_bit,a[M],b[M],c[M];
    unordered_map<int,int> rev;
    inline int lowbit(int x){return x&(-x);}
    inline void update(int x,int k){
        while(x<=num_bit)
            c[x]+=k,x+=lowbit(x);
    }
    inline int query(int x){//1-x的和
        int ans=0;
        while(x)
            ans+=c[x],x-=lowbit(x);
        return ans;
    }
    int main(){
        int n;
        scanf("%d",&n);
        while(n){
            num_bit=n;
            for (int i=1;i<=n;++i)
                scanf("%d",&a[i]),b[i]=a[i],c[i]=0;
            rev.clear(); 
            sort(a+1,a+n+1);
            for(int i=1;i<=n;++i)
                rev[a[i]]=i;
            long long ans=0;
            for(int i=n;i>=1;--i)
                ans+=query(rev[b[i]]),update(rev[b[i]],1);
            printf("%lld
    ",ans);
            scanf("%d",&n);
        }
        return 0;
    }
    
    
  • 相关阅读:
    推荐]历史上最强的绕口令
    超级经理人的关系学:打造黄金人脉
    个人创业的难点和解决之道
    你的人脉关系中不可缺少的十种人[推荐]
    哲理短文一则:揭示最好的成功法则
    [经验交流]太精彩,太有启发性了(经典经典) 转
    权力领域是人才浪费的致命区域
    2006创业完全手册
    爱你我的宝贝(转)
    最远的你是我最近的爱
  • 原文地址:https://www.cnblogs.com/diorvh/p/11980564.html
Copyright © 2011-2022 走看看