hdu 6183 Color it(動態線段樹,cdq分治)

Do you like painting? Little D doesn’t like painting, especially messy color paintings. Now Little B is painting. To prevent him from drawing messy painting, Little D asks you to write a program to maintain following operations. The specific format of these operations is as follows.

00 : clear all the points.

11 xx yy cc : add a point which color is cc at point (x,y)(x,y).

22 xx y1y1 y2y2 : count how many different colors in the square (1,y1)(1,y1) and (x,y2)(x,y2). That is to say, if there is a point (a,b)(a,b) colored cc, that 1≤a≤x1≤a≤x and y1≤b≤y2y1≤b≤y2, then the color cc should be counted.

33 : exit.
Input
The input contains many lines.

Each line contains a operation. It may be ‘0’, ‘1 x y c’ ( 1≤x,y≤106,0≤c≤501≤x,y≤106,0≤c≤50 ), ‘2 x y1 y2’ (1≤x,y1,y2≤1061≤x,y1,y2≤106 ) or ‘3’.

x,y,c,y1,y2x,y,c,y1,y2 are all integers.

Assume the last operation is 3 and it appears only once.

There are at most 150000150000 continuous operations of operation 1 and operation 2.

There are at most 1010 operation 0.

Output
For each operation 2, output an integer means the answer .
Sample Input
0
1 1000000 1000000 50
1 1000000 999999 0
1 1000000 999999 0
1 1000000 1000000 49
2 1000000 1000000 1000000
2 1000000 1 1000000
0
1 1 1 1
2 1 1 2
1 1 2 2
2 1 1 2
1 2 2 2
2 1 1 2
1 2 1 3
2 2 1 2
2 10 1 2
2 10 2 2
0
1 1 1 1
2 1 1 1
1 1 2 1
2 1 1 2
1 2 2 1
2 1 1 2
1 2 1 1
2 2 1 2
2 10 1 2
2 10 2 2
3
Sample Output
2
3
1
2
2
3
3
1
1
1
1
1
1
1

這個題就是說 給你四種操作
0:清空所有的點
1:在(x,y)處添加一個c顏色的點
2:統計(1,y1)到(x,y2) 這個矩陣裏面有多少種不同的顏色
3:退出

因爲顏色只有 50
所以考慮開50棵線段樹,又因爲 50*150000*4 還是會爆,所以縮成一棵,然後發現tle了,因爲離線常數太大,考慮在線操作,因爲每棵樹不超過150000個點,所以完全可以動態開點,利於類似主席樹的思想進行操作。 然後這樣的空間複雜度 是1.5e5*log(1e6) 1,5e5*個21 完全沒問題

*

#include <bits/stdc++.h>
using namespace std;
int op,X,flag;
int T[55],v[3300000],ls[3300000],rs[3300000];
int tot;
const int BUF=30000000;
char Buf[BUF],*buf=Buf;
inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}

void insert(int &x,int l,int r,int d,int val)
{
    if(!x)
    {
        x=++tot;
        v[x]=val;
    }
    if(val<v[x]) v[x]=val;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(d<=mid) insert(ls[x],l,mid,d,val);
    else insert(rs[x],mid+1,r,d,val); 
}
int L,R;
void query(int x,int l,int r)
{
    if(flag||!x) return ;
    if(L<=l&&R>=r)
    {
        if(v[x]<=X) flag=1;
        return ;
    }
    int mid=(l+r)>>1;
    if(L<=mid) query(ls[x],l,mid);
    if(R>mid) query(rs[x],mid+1,r);
}

int main()
{
    fread(Buf,1,BUF,stdin);
    for(int i=0;i<=50;i++) T[i]=0;
    while(1)
    {
        read(op);
        if(op==3) return 0;
        if(op==0)
        {
            for(int i=0;i<=tot;i++) ls[i]=rs[i]=0;
            for(int i=0;i<=50;i++) T[i]=0;
            tot=0;
        }
        if(op==1)
        {
            int x,y,c;
            read(x),read(y),read(c);
            insert(T[c],1,1000000,y,x);
        }
        if(op==2)
        {
            read(X),read(L),read(R);
            int ans=0;
            for(int i=0;i<=50;i++)
            {
                flag=0;
                query(T[i],1,1000000);
                if(flag) ans++;
            }
            printf("%d\n",ans );
        }
    }
}

學了一波cdq分治,其實是把時間當成二分對象,然後遞歸處理,把1~n進行遞歸,每層都是n,
一共logn層,線段樹查詢修改時間也是logn 所以總複雜度是 mlogn*logn 常數比較小,比50個線段樹少得多
題解:這道題一共四個維度,我們可以這樣分配:x軸排序,時間用cdq分治,y座標用線段樹,顏色用位壓縮(64位表示)。

#include <bits/stdc++.h>
using namespace std;

const int N = 150005;
typedef long long ll;
struct node
{
    int op;
    int q[3];
    int t;
}Q[N],SQ[N];
int b[N*2];
int top;
ll sum[N*4];
ll ans[N];
int cmp(node a,node b)
{
    if(a.q[0]==b.q[0]) return a.op<b.op;
    return a.q[0]<b.q[0];
}

void update(int d,int l,int r,int w,int rt,int flag)
{
    if(l==r&&l==d)
    {
        if(!flag)
        sum[rt]|=(1ll<<w);
        else sum[rt]=0;
        return ;
    }
    int mid=(l+r)>>1;
    if(d<=mid) update(d,l,mid,w,rt<<1,flag);
    else update(d,mid+1,r,w,rt<<1|1,flag);
    if(!flag) sum[rt]=sum[rt<<1]|sum[rt<<1|1];
    else sum[rt]=0;
}

ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    {
        return sum[rt];
    }
    ll res=0;
    int mid=(l+r)>>1;
    if(L<=mid) res|=query(L,R,l,mid,rt<<1);
    if(R>mid) res|=query(L,R,mid+1,r,rt<<1|1);
    return res;
}


void solve(int L,int R)
{
    if(L>=R) return ;
    int mid=(L+R)>>1;
    for(int i=L;i<=R;i++)
    {
        if(Q[i].t<=mid&&Q[i].op==1) update(Q[i].q[1],1,top,Q[i].q[2],1,0);
        if(Q[i].t>mid&&Q[i].op==2) ans[Q[i].t]|=query(Q[i].q[1],Q[i].q[2],1,top,1);
    }
    for(int i=L;i<=R;i++)
        if(Q[i].t<=mid&&Q[i].op==1) update(Q[i].q[1],1,top,Q[i].q[2],1,1);
    int l=L;
    for(int i=L;i<=R;i++)
        if(Q[i].t<=mid)
            SQ[l++]=Q[i];
    int r=l;
    for(int i=L;i<=R;i++)
        if(Q[i].t>mid)
            SQ[r++]=Q[i];
    for(int i=L;i<=R;i++)
        Q[i]=SQ[i];
    solve(L,l-1);
    solve(l,R);
}


int main()
{
    int o;
    scanf("%d",&o);
    while(1)
    {
        memset(ans,0,sizeof(ans));
        memset(sum,0,sizeof(sum));
        if(o==3) break;
        int tot=0;top=0;
        while(1)
        {
            scanf("%d",&Q[tot].op),o=Q[tot].op;
            if(o==0||o==3) break;
            scanf("%d%d%d",&Q[tot].q[0],&Q[tot].q[1],&Q[tot].q[2]);
            Q[tot].t=tot;b[top++]=Q[tot].q[1];b[top++]=Q[tot].q[2];
            tot++;
        }
        sort(b,b+top);
        top=unique(b,b+top)-b;
        for(int i=0;i<tot;i++)
        {
            int pos=lower_bound(b,b+top,Q[i].q[1])-b;
            Q[i].q[1]=pos+1;
            if(Q[i].op==2)
            {
                pos=lower_bound(b,b+top,Q[i].q[2])-b;
                Q[i].q[2]=pos+1;
            }
        }
        sort(Q,Q+tot,cmp);
        solve(0,tot-1);
        for(int i=0;i<tot;i++)
        {
            if(Q[i].op==1) continue;
            int ansha=0;
            for(int j=0;j<=50;j++)
                if(ans[i]&(1ll<<j))
                    ansha++;
            printf("%d\n",ansha );
        }
    }
    return 0;
}


發佈了60 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章