1. 程式人生 > >[kuangbin帶你飛]專題七 線段樹

[kuangbin帶你飛]專題七 線段樹

A(hdu 1166 敵兵佈陣 )中文體面,線段樹單點更新,求一段區間和

#include<stdio.h>
#include<string.h>
#include<stack>
#include<string>
#include<math.h>
#include<queue>
#include<set>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
#define LL long long
#define inf 1<<31
#define N 50010
#define mod 1000000007
struct node
{
    int l,r,sum;
}tree[N<<2];
void pushup(int rt)
{
    tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
}
void build(int l,int r,int rt)
{
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].sum=0;
    if(l==r)
    {
        scanf("%d",&tree[rt].sum);
        return ;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
void updata(int x,int y,int rt)
{
    if(tree[rt].l==tree[rt].r)
    {
        tree[rt].sum+=y;
        return ;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(x<=mid) updata(x,y,rt<<1);
    else updata(x,y,rt<<1|1);
    pushup(rt);
}
int query(int x,int y,int rt)
{
    if(tree[rt].l==x&&tree[rt].r==y)
    {
        return tree[rt].sum;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(y<=mid) return query(x,y,rt<<1);
    else if(x>mid) return query(x,y,rt<<1|1);
    else
        return query(x,mid,rt<<1)+query(mid+1,y,rt<<1|1);
}
int main()
{
    int i,j,n,m,t,x,y,ca=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        build(1,n,1);
        char s[10];
        printf("Case %d:\n",++ca);
        while(scanf("%s",s),s[0]!='E')
        {
            scanf("%d%d",&x,&y);
            if(s[0]=='Q')
                printf("%d\n",query(x,y,1));
            else if(s[0]=='A')
                updata(x,y,1);
            else if(s[0]=='S')
                updata(x,-y,1);;
        }
    }
    return 0;
}
B(hdu 1754 I Hate It)中文體面,線段樹單點更新,求區間最大值
#include<stdio.h>
#include<string.h>
#include<stack>
#include<string>
#include<math.h>
#include<queue>
#include<set>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
#define LL long long
#define inf 1<<31
#define N 200010
struct node
{
	int l,r,Max;
}tree[N<<2];
void build(int l,int r,int rt)
{
	tree[rt].l=l;
	tree[rt].r=r;
	if(l==r)
	{
		scanf("%d",&tree[rt].Max);
		return ;
	}
	int mid=(r+l)>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,rt<<1|1);
	tree[rt].Max=max(tree[rt<<1].Max,tree[rt<<1|1].Max);
}
int ans;
void query(int l,int r,int rt)
{
	if(tree[rt].l==l&&tree[rt].r==r)
	{
		ans=max(ans,tree[rt].Max);
		return ;
	}
	int mid=(tree[rt].l+tree[rt].r)>>1;
	if(l>mid) query(l,r,rt<<1|1);
	else if(r<=mid) query(l,r,rt<<1);
	else
	{
		query(l,mid,rt<<1);
		query(mid+1,r,rt<<1|1);
	}
}
void updata(int x,int y,int rt)
{
	if(tree[rt].l==tree[rt].r)
	{
		tree[rt].Max=y;
		return ;
	}
	int mid=(tree[rt].l+tree[rt].r)>>1;
	if(x>mid) updata(x,y,rt<<1|1);
	else updata(x,y,rt<<1);
	tree[rt].Max=max(tree[rt<<1].Max,tree[rt<<1|1].Max);
}
int main()
{
	int i,j,n,m,x,y;
	char s[3];
	while(scanf("%d%d",&n,&m)!=-1)
	{
		build(1,n,1);
		for(i=1;i<=m;i++)
		{
			scanf("%s%d%d",s,&x,&y);
			if(s[0]=='Q')
			{
				ans=-1;
				query(x,y,1);
				printf("%d\n",ans);
			}
			else updata(x,y,1);
		}
	}
	return 0;
}
C(poj 3468 A Simple Problem with Integers)線段樹的區間更新區間求和
#include<stdio.h>
#include<string.h>
#include<stack>
#include<string>
#include<math.h>
#include<queue>
#include<set>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
#define LL long long
#define inf 1<<31
#define N 100010
struct node
{
    int l,r;
    LL sum,add;//加的數不直接更新到葉子節點,而是先存到add中
}tree[N<<2];
void pushup(int rt)
{
    tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
}
void build(int l,int r,int rt)
{
    tree[rt].l=l;tree[rt].r=r;
    tree[rt].sum=tree[rt].add=0;
    if(l==r)
    {
        scanf("%lld",&tree[rt].sum);
        return ;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
void pushdown(int rt)
{
    int len=tree[rt].r-tree[rt].l+1;
    tree[rt<<1].add+=tree[rt].add;
    tree[rt<<1|1].add+=tree[rt].add;

    tree[rt<<1].sum+=tree[rt].add*(len-len/2);
    tree[rt<<1|1].sum+=tree[rt].add*(len/2);
    tree[rt].add=0;
}
LL query(int x,int y,int rt)
{
    if(tree[rt].l==x&&tree[rt].r==y)
        return tree[rt].sum;
    int mid=(tree[rt].l+tree[rt].r)>>1;
    pushdown(rt);
    if(y<=mid) return query(x,y,rt<<1);
    else if(x>mid) return query(x,y,rt<<1|1);
    else return query(x,mid,rt<<1)+query(mid+1,y,rt<<1|1);
}
void updata(int x,int y,LL z,int rt)
{
    if(tree[rt].l==x&&tree[rt].r==y)
    {
        tree[rt].add+=z;
        tree[rt].sum+=(y-x+1)*z;
        return ;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    pushdown(rt);
    if(y<=mid) updata(x,y,z,rt<<1);
    else if(x>mid) updata(x,y,z,rt<<1|1);
    else {
        updata(x,mid,z,rt<<1);
        updata(mid+1,y,z,rt<<1|1);
    }
    pushup(rt);
}
int main()
{
    int i,j,n,m;
    char s[3];
    int x,y;
    LL z;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        build(1,n,1);
        while(m--)
        {
            scanf("%s",s);
            if(s[0]=='Q')
            {
                scanf("%d%d",&x,&y);
                printf("%lld\n",query(x,y,1));
            }
            else
            {
                scanf("%d%d%lld",&x,&y,&z);
                updata(x,y,z,1);
            }
        }
    }
    return 0;
}
D(poj 2528  Mayor's posters )線段樹+離散化,就是在牆上貼海報,當前貼的海報可以把以前的海報覆蓋掉,問最後還能看見多少海報
#include<stdio.h>
#include<string.h>
#include<stack>
#include<string>
#include<math.h>
#include<queue>
#include<set>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
#define LL long long
#define inf 1<<31
#define N 20010
struct node
{
    int l,r,c;
}tree[N<<2];
struct Line
{
    int l,r;
}a[N];
int key[N],tot,ans;
bool mark[N];
void build(int l,int r,int rt)
{
    tree[rt].l=l;tree[rt].r=r;
    tree[rt].c=0;
    if(l==r) return ;
    int mid=(tree[rt].l+tree[rt].r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
}
int find_p(int x)
{
    int low=1,high=tot;
    while(low<=high)
    {
        int mid=(low+high)>>1;
        if(key[mid]==x) return mid;
        else if(x<key[mid])
            high=mid-1;
        else low=mid+1;
    }
}
void updata(int l,int r,int c,int rt)
{
    if(tree[rt].l==l&&tree[rt].r==r)
    {
        tree[rt].c=c;
        return ;
    }
    if(tree[rt].c)
    {
        tree[rt<<1].c=tree[rt<<1|1].c=tree[rt].c;
        tree[rt].c=0;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(r<=mid) updata(l,r,c,rt<<1);
    else if(l>mid) updata(l,r,c,rt<<1|1);
    else
    {
        updata(l,mid,c,rt<<1);
        updata(mid+1,r,c,rt<<1|1);
    }
}
void query(int rt)
{
    if(tree[rt].c)
    {
        if(mark[tree[rt].c]==0)
        {
            mark[tree[rt].c]=1;
            ans++;
        }
        return ;
    }
    query(rt<<1);
    query(rt<<1|1);
}
int main()
{
    int i,j,n,m,t;
    scanf("%d",&t);
    while(t--)
    {
        memset(mark,0,sizeof(mark));
        scanf("%d",&n);
        tot=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i].l,&a[i].r);
            key[++tot]=a[i].l;key[++tot]=a[i].r;
        }
        sort(key+1,key+1+tot);
        tot=unique(key+1,key+1+tot)-(key+1);//陣列去重
//        printf("%d\n",tot);
        build(1,tot,1);
        for(i=1;i<=n;i++)//離散化
        {
            int L=find_p(a[i].l);
            int R=find_p(a[i].r);
            updata(L,R,i,1);
        }
        ans=0;
        query(1);
        printf("%d\n",ans);
    }
    return 0;
}
E(hdu 1698 just a hook) 還是區間操作,程式碼點選開啟連結

F(zoj 1610 Count the Colors)

#include<stdio.h>
#include<string.h>
#include<stack>
#include<string>
#include<math.h>
#include<queue>
#include<set>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
#define LL long long
#define inf 1<<31
#define N 8010
struct node
{
    int l,r,c;
}tree[N<<2];
int col[N],ans[N];//col[i]是i位置顏色的種類,ans[i]是顏色i的段數
void build(int l,int r,int rt)
{
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].c=-1;
    if(r-l==1) return ;//塗色是一小段區間
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid,r,rt<<1|1);
}
void updata(int l,int r,int c,int rt)
{
    if(tree[rt].l==l&&tree[rt].r==r)
    {
        tree[rt].c=c;
        return ;
    }
    if(tree[rt].r-tree[rt].l==1) return ;
    
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(tree[rt].c!=-1)
    {
        tree[rt<<1].c=tree[rt<<1|1].c=tree[rt].c;
        tree[rt].c=-1;
    }
    if(r<=mid) updata(l,r,c,rt<<1);
    else if(l>=mid) updata(l,r,c,rt<<1|1);
    else
    {
        updata(l,mid,c,rt<<1);
        updata(mid,r,c,rt<<1|1);
    }
}
void query(int rt)
{
    if(tree[rt].c!=-1)
    {
        for(int i=tree[rt].l;i<tree[rt].r;i++)
            col[i]=tree[rt].c;
        return ;
    }
    if(tree[rt].r-tree[rt].l==1) return ;
    
    query(rt<<1);
    query(rt<<1|1);
}
int main()
{
    int i,j,n,m;
    while(scanf("%d",&n)!=EOF)
    {
        int x,y,z;
        build(0,8000,1);
        for(i=0;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            updata(x,y,z,1);
        }
        memset(ans,0,sizeof(ans));
        memset(col,-1,sizeof(col));
        query(1);
        for(i=0;i<=8000;i++)
        {
            if(col[i]==-1) continue;
            if(col[i]!=col[i+1])
                ans[col[i]]++;
        }
        for(i=0;i<=8000;i++)
        {
            if(ans[i]==0) continue;
            printf("%d %d\n",i,ans[i]);
        }
        puts("");
    }
    return 0;
}

G 簡單的單點更新

#include<stdio.h>
#include<string.h>
#include<stack>
#include<string>
#include<math.h>
#include<queue>
#include<set>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
#define LL long long
#define inf 1<<30
#define N 50010
struct node
{
	int l,r,Min,Max;
}tree[N<<2];
int resmin,resmax;
void build(int l,int r,int rt)
{
	tree[rt].l=l;
	tree[rt].r=r;
	if(l==r)
	{
		scanf("%d",&tree[rt].Min);
		tree[rt].Max=tree[rt].Min;
		return ;
	}
	int mid=(r+l)>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,rt<<1|1);
	tree[rt].Min=min(tree[rt<<1].Min,tree[rt<<1|1].Min);
	tree[rt].Max=max(tree[rt<<1].Max,tree[rt<<1|1].Max);
}
void query(int l,int r,int rt)
{
	if(tree[rt].l==l&&tree[rt].r==r)
	{
		resmin=min(resmin,tree[rt].Min);
		resmax=max(resmax,tree[rt].Max);
		return ;
	}
	int mid=(tree[rt].l+tree[rt].r)>>1;
	if(l>mid) query(l,r,rt<<1|1);
	else if(r<=mid) query(l,r,rt<<1);
	else
	{
		query(l,mid,rt<<1);
		query(mid+1,r,rt<<1|1);
	}
}
int main()
{
	int m,n,j,i,a,b;
	while(scanf("%d%d",&n,&m)!=-1)
	{
		build(1,n,1);
		for(i=0;i<m;i++)
		{
			resmin=inf;resmax=-inf;
			scanf("%d%d",&a,&b);
			query(a,b,1);
			printf("%d\n",resmax-resmin);
		}
	}
	return 0;
}
I(hdu 1540 Tunnel Warfare)單點更新,區間合併、查詢
#include<stdio.h>
#include<string.h>
#include<stack>
#include<string>
#include<math.h>
#include<queue>
#include<set>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
#define LL long long
#define inf 1<<30
#define N 50010
struct node
{
    int l,r,lans,rans,ans;
}tree[N<<2];
void pushup(int rt)
{
    if(tree[rt<<1].ans==tree[rt<<1].r-tree[rt<<1].l+1)
        tree[rt].lans=tree[rt<<1].ans+tree[rt<<1|1].lans;
    else tree[rt].lans=tree[rt<<1].lans;

    if(tree[rt<<1|1].ans==tree[rt<<1|1].r-tree[rt<<1|1].l+1)
        tree[rt].rans=tree[rt<<1|1].ans+tree[rt<<1].rans;
    else tree[rt].rans=tree[rt<<1|1].rans;

    tree[rt].ans= max(max(tree[rt<<1].ans,tree[rt<<1|1].ans),tree[rt<<1].rans+tree[rt<<1|1].lans);
}
void build(int l,int r,int rt)
{
    tree[rt].l=l;tree[rt].r=r;
    tree[rt].lans=tree[rt].rans=tree[rt].ans=r-l+1;
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
}
void updata(int x,int rt,int c)
{
    if(tree[rt].l==tree[rt].r)
    {
        tree[rt].ans=tree[rt].lans=tree[rt].rans=c;
        return ;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(x<=mid) updata(x,rt<<1,c);
    else updata(x,rt<<1|1,c);
    pushup(rt);
}
int query(int x,int rt)
{
    if(tree[rt].ans==0||tree[rt].ans==tree[rt].r-tree[rt].l+1)
        return tree[rt].ans;
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(x<=mid)
    {
        if(x>=tree[rt<<1].r-tree[rt<<1].rans+1)
            return tree[rt<<1].rans+tree[rt<<1|1].lans;
        else return query(x,rt<<1);
    }
    else
    {
        if(x<=tree[rt<<1|1].l+tree[rt<<1|1].lans-1)
            return tree[rt<<1].rans+tree[rt<<1|1].lans;
        else return query(x,rt<<1|1);
    }
}
int main()
{
    int i,j,n,m,x;
    char str[3];
    while(scanf("%d%d",&n,&m)!=-1)
    {
        stack<int>s;
        while(!s.empty()) s.pop();
        build(1,n,1);
        while(m--)
        {
            scanf("%s",str);
            if(str[0]=='D')
            {
                scanf("%d",&x);
                updata(x,1,0);
                s.push(x);
            }
            else if(str[0]=='Q')
            {
                scanf("%d",&x);
                printf("%d\n",query(x,1));
            }
            else
            {
                x=s.top();
                s.pop();
                updata(x,1,1);
            }
        }
    }
    return 0;
}

P(hdu 1542 Atlantis)掃描線求矩形面積

#include<stdio.h>
#include<string.h>
#include<stack>
#include<string>
#include<math.h>
#include<queue>
#include<set>
#include<algorithm>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
#define LL long long
#define inf 1<<30
#define N 210
struct node
{
    int l,r;
    int c;//c用來記錄重疊情況
    double cnt,lf,rf;
    //cnt用來計算y的長度,rf,lf分別是對應的左右真實的浮點數端點
}tree[N<<2];
struct Line
{
    double x,y1,y2;
    int f;
}line[N];
//把一段段平行於y軸的線段表示成陣列 ,
//x是線段的x座標,y1,y2線段對應的下端點和上端點的座標
//一個矩形 ,左邊的那條邊f為1,右邊的為-1,
//用來記錄重疊情況,可以根據這個來計算,nod節點中的c
double y[N];//記錄y座標的陣列
bool cmp(Line a,Line b)
{
    return a.x<b.x;
}
void build(int l,int r,int rt)
{
    tree[rt].l=l;tree[rt].r=r;
    tree[rt].cnt=tree[rt].c=0;
    tree[rt].lf=y[l];tree[rt].rf=y[r];
    if(l+1==r) return ;
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid,r,rt<<1|1);
}
void calen(int rt)
{
    if(tree[rt].c>0)
    {
        tree[rt].cnt=tree[rt].rf-tree[rt].lf;
        return ;
    }
    if(tree[rt].l+1==tree[rt].r) tree[rt].cnt=0;
    else tree[rt].cnt=tree[rt<<1].cnt+tree[rt<<1|1].cnt;
}
void updata(int rt,Line e)
{
    if(e.y1==tree[rt].lf&&tree[rt].rf==e.y2)
    {
        tree[rt].c+=e.f;
        calen(rt);
        return ;
    }
    if(e.y2<=tree[rt<<1].rf) updata(rt<<1,e);
    else if(e.y1>=tree[rt<<1|1].lf) updata(rt<<1|1,e);
    else
    {
        Line tmp=e;
        tmp.y2=tree[rt<<1].rf;
        updata(rt<<1,tmp);
        tmp=e;
        tmp.y1=tree[rt<<1|1].lf;
        updata(rt<<1|1,tmp);
    }
    calen(rt);
}
int main()
{
    int i,n,j,t,ca=1;
    double x1,x2,y1,y2;
    while(scanf("%d",&n),n)
    {
        t=1;
        for(i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[t].x=x1;line[t].y1=y1;line[t].y2=y2;line[t].f=1;
            y[t]=y1; t++;
            line[t].x=x2;line[t].y1=y1;line[t].y2=y2;line[t].f=-1;
            y[t]=y2; t++;
        }
        sort(line+1,line+t,cmp);
        sort(y+1,y+t);
        build(1,t-1,1);
        updata(1,line[1]);
        double ans=0;
        for(i=2;i<t;i++)
        {
            ans+=tree[1].cnt*(line[i].x-line[i-1].x);
            updata(1,line[i]);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n",ca++,ans);
    }
    return 0;
}