线段树题集

hdu1199-Color the Ball(区间覆盖)

/*
题意:有无限个球排成一行,刚开始是黑色,然后他可以给一段区间染成
黑色或白色,最后要求找出最长连续白球序列,如果有多解,输出最左边
的,不存在输出Oh, my god

解析:因为是无限大,所以要离散化,我为了方便,将坐标扩大了3倍
每次插入区间的时候插入[L,R+1],插入完之后整个压下去,记录每个位置
是白色还是黑色,然后更新答案即可,具体细节见代码。
*/
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<sstream>
#include<utility>
#include<iterator>
using namespace std;
const int INF=1e9+7;
const double eps=1e-7;
typedef __int64 LL;
const int maxn=2005;
int N,Size;
struct node
{
    int L,R;
    char C[2];
}Nod[maxn];
vector<int> ve;
struct Tree
{
    int le,ri,lazy;
}tree[3*4*2*maxn];
int mark[3*2*maxn];
void GetPos()
{
    sort(ve.begin(),ve.end());
    ve.erase(unique(ve.begin(),ve.end()),ve.end());
    for(int i=0;i<N;i++)   //离散化
    {
        node& t=Nod[i];
        t.L=lower_bound(ve.begin(),ve.end(),t.L)-ve.begin();
        t.L*=3;  //扩大3倍
        t.R=lower_bound(ve.begin(),ve.end(),t.R)-ve.begin();
        t.R*=3;
    }
}
void build_tree(int id,int le,int ri)
{
    Tree& e=tree[id];
    e.le=le,e.ri=ri,e.lazy=-1;
    if(le==ri) return;
    int mid=(le+ri)/2;
    build_tree(id*2,le,mid);
    build_tree(id*2+1,mid+1,ri);
    return;
}
void pushdown(int id)
{
    if(tree[id].lazy!=-1) 
    {
        tree[id*2].lazy=tree[id*2+1].lazy=tree[id].lazy;
        tree[id].lazy=-1;
    }
}
void update(int id,int x,int y,int c)
{
    Tree& e=tree[id];
    int le=e.le,ri=e.ri;
    if(x<=le&&ri<=y){ e.lazy=c; return; }
    pushdown(id);
    int mid=(le+ri)/2;
    if(x<=mid) update(id*2,x,y,c);
    if(y>mid)  update(id*2+1,x,y,c);
    return;
}
void query(int id)
{
    Tree& e=tree[id];
    int le=e.le,ri=e.ri;
    if(le==ri)
    {
        mark[le]=abs(e.lazy);
        return;
    }
    pushdown(id);
    query(id*2);
    query(id*2+1);
    return;
}
int GetAns(int a,int b,int& ra,int& rb)
{
    ra=ve[a/3],rb=ve[(b+1)/3];
    if(a%3!=0) ra++; //不为0说明左端点的这个位置被占了,要加1
    if(b%3!=1) rb--; //不为1说明右端点的这个位置被占了,要减1
    return rb-ra+1;
}
void solve()
{
    Size=ve.size()-1;
    build_tree(1,0,3*Size+1); //建树
    for(int i=0;i<N;i++)
    {
        node& t=Nod[i];
        if(t.C[0]=='w') update(1,t.L,t.R+1,0);  //0代表白色,
                             //R+1是用于后面判断右端点是否被覆盖
        else update(1,t.L,t.R+1,1);  //1代表黑色
    }
    query(1); //整个压下去
    int ret=0;
    int pre=-1;
    vector<pair<int,int> > V;
    V.clear();

    for(int i=0;i<=3*Size+1;i++)
    {
        if(mark[i]) //被标记为黑色
        {
            if(pre!=-1) V.push_back(make_pair(pre,i-1)); //找到一段
            pre=-1;
            continue;
        }
        if(pre==-1) pre=i;//当前是白色起点位置,之前是黑色
    }
    if(pre!=-1) V.push_back(make_pair(pre,3*Size+1)); //最后还有一段
    int ansa=-1,ansb=-1;
    for(int i=0;i<V.size();i++)
    {
        int a=V[i].first,b=V[i].second;
        int ra,rb;
        int tt=GetAns(a,b,ra,rb); 
        if(ret<tt){ ret=tt; ansa=ra,ansb=rb; } //找答案
    }
    if(ansa==-1) printf("Oh, my god\n");  //无解
    else printf("%d %d\n",ansa,ansb);   //打印两个位置
}
int main()
{
    while(scanf("%d",&N)!=EOF)
    {
        ve.clear();
        for(int i=0;i<N;i++)
        {
           scanf("%d%d%s",&Nod[i].L,&Nod[i].R,Nod[i].C);
           if(Nod[i].L>Nod[i].R) swap(Nod[i].L,Nod[i].R);//以防万一才写的
           ve.push_back(Nod[i].L); ve.push_back(Nod[i].R);
        }
        GetPos();
        solve();
    }
    return 0;
}
View Code

hdu1255- 覆盖的面积(扫描线+矩形多重覆盖)

/*
题意:计算至少覆盖两次的区域的面积

解析:裸的扫描线,但是是超过2次覆盖,这里再增加一个
ss这个变量,代表两次及以上覆盖的长度,我也是看别人
博客做的,固定的模式。。。
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
typedef __int64 LL; 
const int maxn=2005; 
struct node 
{ 
    double L,R,H; 
    int c; 
    node(double L=0,double R=0,double H=0,int c=1) 
    :L(L),R(R),H(H),c(c){} 
    bool operator < (const node& t) const
    { 
        return H<t.H; 
    } 
}Nod[maxn]; 
int N,num; 
double A[maxn]; 
struct Tree 
{ 
    int le,ri,d; 
    double s,ss; 
}tree[8*maxn]; 
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le,e.ri=ri,e.d=0; 
    e.s=0,e.ss=0; 
    if(le==ri) return; 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    return; 
} 
void pushup(int id) 
{ 
    Tree& fa=tree[id]; 
    Tree& lson=tree[id*2]; 
    Tree& rson=tree[id*2+1]; 
    int le=fa.le,ri=fa.ri; 
    if(fa.d) fa.s=A[ri+1]-A[le]; 
    else if(le==ri) fa.s=0; 
    else fa.s=lson.s+rson.s; 
    if(fa.d>1) fa.ss=A[ri+1]-A[le]; 
    else if(le==ri) fa.ss=0; 
    else if(fa.d==1) fa.ss=lson.s+rson.s; 
    else fa.ss=lson.ss+rson.ss; 
} 
void update(int id,int x,int y,int c) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x==le&&ri==y) 
    { 
        e.d+=c; 
        pushup(id); 
        return; 
    } 
    int mid=(le+ri)/2; 
    if(y<=mid) update(id*2,x,y,c); 
    else if(x>mid) update(id*2+1,x,y,c); 
    else
    { 
        update(id*2,x,mid,c); 
        update(id*2+1,mid+1,y,c); 
    } 
    pushup(id); 
    return; 
} 
double solve() 
{ 
    sort(Nod+1,Nod+num+1); 
    sort(A+1,A+num+1); 
    int k=1; 
    for(int i=2;i<=num;i++) if(A[i]!=A[k]) A[++k]=A[i]; //去重
    build_tree(1,1,k); 
    double ret=0; 
    for(int i=1;i<num;i++) 
    { 
        node& t=Nod[i]; 
        int x=lower_bound(A+1,A+k+1,t.L)-A; //下标
        int y=lower_bound(A+1,A+k+1,t.R)-A-1; 
        update(1,x,y,t.c); //更新
        ret+=tree[1].ss*(Nod[i+1].H-Nod[i].H); 
    } 
    return ret; 
} 
int main() 
{ 
    int T; 
    scanf("%d",&T); 
    while(T--) 
    { 
        scanf("%d",&N); 
        num=0; 
        double x1,y1,x2,y2; 
        for(int i=1;i<=N;i++) 
        { 
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); //输入坐标
            Nod[++num]=node(x1,x2,y1,1);  //增加下边
            A[num]=x1; //为了离散化所用
            Nod[++num]=node(x1,x2,y2,-1); //增加上边
            A[num]=x2; 
        } 
        printf("%.2lf\n",solve()); 
    } 
    return 0; 
}
View Code

hdu3074-Multiply game(成段更新取乘积)

/*
题意:计算一段区间的乘积模上1000000007

解析:裸的线段树成段更新,计算的时候乘积取模就可以了
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
typedef __int64 LL; 
#define fa tree[id] 
#define lson tree[id*2] 
#define rson tree[id*2+1] 
const int maxn=50005; 
const LL mod=1e9+7; 
struct Tree 
{ 
    int le,ri; 
    LL sum; 
}tree[4*maxn]; 
void pushup(int id){ fa.sum=(lson.sum*rson.sum)%mod; } 
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le,e.ri=ri; 
    if(le==ri) 
    { 
        scanf("%I64d",&e.sum); 
        return; 
    } 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    pushup(id); 
    return; 
} 
void update(int id,int k,LL v) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(le==ri) { e.sum=v%mod; return; } 
    int mid=(le+ri)/2; 
    if(k<=mid) update(id*2,k,v); 
    else update(id*2+1,k,v); 
    pushup(id); 
    return; 
} 
LL query(int id,int x,int y) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) return e.sum; 
    LL ret=1; 
    int mid=(le+ri)/2; 
    if(x<=mid) ret*=query(id*2,x,y); 
    if(y>mid)  ret*=query(id*2+1,x,y); 
    return ret%mod; 
} 
int main() 
{ 
    int T; 
    scanf("%d",&T); 
    while(T--) 
    { 
        int N; 
        scanf("%d",&N); 
        build_tree(1,1,N); 
        int M; 
        scanf("%d",&M); 
        int op,x,y; 
        for(int k=1;k<=M;k++) 
        { 
            scanf("%d%d%d",&op,&x,&y); 
            if(op==0) printf("%I64d\n",query(1,x,y)); 
            else update(1,x,(LL)y); 
        } 
    } 
    return 0; 
} 
View Code

hdu3255-Farming(扫描线)

/*
题意:有N种不同的蔬菜,每种蔬菜有一个价格,给出M
块矩形田地以及这块田地上种植的是哪种蔬菜。覆盖的
地方价格最高的那种蔬菜会生存下去。问最多可以获得
多大的收益。

解析:对价格排个序,然后开始枚举price[i],把种植价格
大于等于price[i]的田地加进去进行扫描线,答案加上面
积乘上price[i]-price[i-1]的差值。
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
typedef __int64 LL; 
#define fa tree[id] 
#define lson tree[id*2] 
#define rson tree[id*2+1] 
#define e tree[id] 
const int maxn=60005; 
struct Po 
{ 
    int x1,y1,x2,y2,val; 
    Po(int x1=0,int y1=0,int x2=0,int y2=0,int val=0) 
    :x1(x1),y1(y1),x2(x2),y2(y2),val(val){} 
}P[maxn]; 
struct node 
{ 
    int L,R,H,s; 
    node(int L=0,int R=0,int H=0,int s=1) 
    :L(L),R(R),H(H),s(s){} 
    bool operator < (const node& t) const
    { 
        return H<t.H; 
    } 
}Nod[maxn]; 
struct Tree 
{ 
    int le,ri,c,sum; 
}tree[4*maxn]; 
int N,M,num,price[4],A[maxn]; 
void AddLine(Po& t) 
{ 
    Nod[++num]=node(t.x1,t.x2,t.y1,1); 
    A[num]=t.x1; 
    Nod[++num]=node(t.x1,t.x2,t.y2,-1); 
    A[num]=t.x2; 
} 
void build_tree(int id,int le,int ri) 
{ 
    e.le=le,e.ri=ri,e.c=e.sum=0; 
    if(le==ri) return; 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    return; 
} 
void pushup(int id) 
{ 
    int le=fa.le,ri=fa.ri; 
    if(fa.c) fa.sum=A[ri+1]-A[le]; 
    else if(le==ri) fa.sum=0; 
    else fa.sum=lson.sum+rson.sum; 
} 
void update(int id,int x,int y,int c) 
{ 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) 
    { 
        e.c+=c; 
        pushup(id); 
        return; 
    } 
    int mid=(le+ri)/2; 
    if(x<=mid) update(id*2,x,y,c); 
    if(y>mid)  update(id*2+1,x,y,c); 
    pushup(id); 
    return; 
} 
LL Get() //扫描线
{ 
    sort(Nod+1,Nod+num+1); 
    sort(A+1,A+num+1); 
    int k=1; 
    for(int i=2;i<=num;i++) if(A[i]!=A[k]) A[++k]=A[i]; //去重
    build_tree(1,1,k); //建树
    LL ret=0; 
    for(int i=1;i<num;i++) //模板
    { 
        node& t=Nod[i]; 
        int x=lower_bound(A+1,A+k+1,t.L)-A; 
        int y=lower_bound(A+1,A+k+1,t.R)-A-1; 
        if(x>y) continue; 
        update(1,x,y,t.s); 
        ret+=(LL)tree[1].sum*(Nod[i+1].H-Nod[i].H); 
    } 
    return ret; 
} 
LL solve() 
{ 
    price[0]=0; 
    sort(price+1,price+M+1); 
    LL ret=0; 
    for(int i=1;i<=M;i++) //依次加起来
    { 
        num=0; 
        for(int j=1;j<=N;j++) 
            if(P[j].val>=price[i]) AddLine(P[j]); //增加这条边 
        ret+=Get()*(price[i]-price[i-1]); //把差值加上
    } 
    return ret; 
} 
int main() 
{ 
    int T,Case=0; 
    scanf("%d",&T); 
    while(T--) 
    { 
        scanf("%d%d",&N,&M); 
        for(int i=1;i<=M;i++) scanf("%d",&price[i]); 
        int x1,y1,x2,y2,type; 
        for(int i=1;i<=N;i++) 
        { 
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&type); 
            P[i]=Po(x1,y1,x2,y2,price[type]); 
        } 
        printf("Case %d: %I64d\n",++Case,solve()); 
    } 
    return 0; 
} 
View Code

hdu3642-Get The Treasury(扫描线+三重覆盖)

/*
题意:求覆盖至少三次的体积

解析:离散化高度,扫描线求面积,覆盖三次
增加3个变量s,ss,sss,分别记录至少覆盖一次,两次,三次
的区间长度
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
typedef long long LL; 
#define fa tree[id] 
#define lson tree[id*2] 
#define rson tree[id*2+1] 
#define e tree[id] 
const int maxn=2005; 
int N,num; 
struct Point 
{ 
    int x1,y1,z1,x2,y2,z2; 
    Point(int x1=0,int y1=0,int z1=0,int x2=0,int y2=0,int z2=0) 
    :x1(x1),y1(y1),z1(z1),x2(x2),y2(y2),z2(z2){} 
}P[maxn]; 
struct node 
{ 
    int L,R,H,s; 
    node(int L=0,int R=0,int H=0,int s=0) 
    :L(L),R(R),H(H),s(s){} 
    bool operator < (const node& t) const
    { 
        return H<t.H; 
    } 
}Nod[maxn]; 
struct Tree 
{ 
    int le,ri,c; 
    int s,ss,sss; 
}tree[4*maxn]; 
int A[maxn]; 
void AddLine(Point& p) 
{ 
    Nod[++num]=node(p.x1,p.x2,p.y1,1); 
    A[num]=p.x1; 
    Nod[++num]=node(p.x1,p.x2,p.y2,-1); 
    A[num]=p.x2; 
} 
void build_tree(int id,int le,int ri) 
{ 
    e.le=le,e.ri=ri,e.s=e.ss=e.sss=0,e.c=0; 
    if(le==ri) return; 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    return; 
} 
void pushup(int id) //这个地方是重点
{ 
    int le=fa.le,ri=fa.ri; 
    if(fa.c) fa.s=A[ri+1]-A[le]; 
    else if(le==ri) fa.s=0; 
    else fa.s=lson.s+rson.s; 
  
    if(fa.c>=2) fa.ss=A[ri+1]-A[le]; 
    else if(le==ri) fa.ss=0; 
    else if(fa.c==1) fa.ss=lson.s+rson.s; 
    else fa.ss=lson.ss+rson.ss; 
  
    if(fa.c>=3) fa.sss=A[ri+1]-A[le]; 
    else if(le==ri) fa.sss=0; 
    else if(fa.c==2) fa.sss=lson.s+rson.s; 
    else if(fa.c==1) fa.sss=lson.ss+rson.ss; 
    else fa.sss=lson.sss+rson.sss; 
} 
void update(int id,int x,int y,int c) 
{ 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) 
    { 
        e.c+=c; 
        pushup(id); 
        return; 
    } 
    int mid=(le+ri)/2; 
    if(x<=mid) update(id*2,x,y,c); 
    if(y>mid)  update(id*2+1,x,y,c); 
    pushup(id); 
    return; 
} 
LL Get()   //扫描线模板
{ 
    if(num<6) return 0; 
    sort(Nod+1,Nod+num+1); 
    sort(A+1,A+num+1); 
    int k=1; 
    for(int i=2;i<=num;i++) if(A[i]!=A[k]) A[++k]=A[i]; 
    build_tree(1,1,k-1); 
    int x,y; 
    LL ret=0; 
    for(int i=1;i<num;i++) 
    { 
        node& t=Nod[i]; 
        x=lower_bound(A+1,A+k+1,t.L)-A; 
        y=lower_bound(A+1,A+k+1,t.R)-A-1; 
        update(1,x,y,t.s); 
        ret+=(LL)tree[1].sss*(Nod[i+1].H-Nod[i].H); 
    } 
    return ret; 
} 
int B[maxn]; 
LL solve() 
{ 
    LL ret=0; 
    sort(B+1,B+num+1); 
    int k=1; 
    for(int i=2;i<=num;i++) if(B[i]!=B[k]) B[++k]=B[i]; //离散化高度
    for(int i=2;i<=k;i++) //枚举
    { 
        num=0; 
        for(int j=1;j<=N;j++) 
        { 
            Point& p=P[j]; 
            if(p.z1<B[i]&&p.z2>=B[i]) AddLine(p); //把边加进去
        } 
        LL add=Get(); 
        ret+=add*((LL)B[i]-B[i-1]); //加上这一层的体积
    } 
    return ret; 
} 
int main() 
{ 
    int T,Case=0; 
    scanf("%d",&T); 
    while(T--) 
    { 
        scanf("%d",&N); 
        int x1,x2,y1,y2,z1,z2; 
        num=0; 
        for(int i=1;i<=N;i++) 
        { 
            scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2); 
            P[i]=Point(x1,y1,z1,x2,y2,z2); //增加一个长方体
            B[++num]=z1; 
            B[++num]=z2; 
        } 
        LL ans=solve(); 
        printf("Case %d: %lld\n",++Case,ans); 
    } 
    return 0; 
} 
View Code

hdu3911-Black And White(线段树01翻转)

/*
题意:可以将一段区间黑变成白,白变成黑,查询时问最长连续黑色的
长度是多少

解析:线段树区间合并,设置wll(白色左边连续的长度),wrl(白色右边连续的长度)
wml(白色最长的连续长度),bll(黑色左边连续的长度),brl(黑色右边连续的长度)
bml(黑色最长的连续长度)。没次pushup都要更新这些值,具体细节见代码。
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
typedef __int64 LL; 
#define fa  tree[id] 
#define lson tree[id*2] 
#define rson tree[id*2+1] 
const int maxn=100005; 
struct Tree 
{ 
    int le,ri,len,c,d; 
    int wll,wrl,wml; 
    int bll,brl,bml; 
    void init() 
    { 
        bll=brl=bml=len*c; 
        wll=wrl=wml=len*(c^1); 
    } 
    void f() 
    { 
        swap(bll,wll); swap(brl,wrl); swap(bml,wml); //黑白交换
    } 
}tree[4*maxn]; 
int N,M; 
void pushup(int id) 
{ 
    fa.bll=lson.bll; 
    if(fa.bll==lson.len) fa.bll+=rson.bll; //延伸到右边去
    fa.brl=rson.brl; 
    if(fa.brl==rson.len) fa.brl+=lson.brl; //延伸到左边去
    fa.bml=max(lson.bml,rson.bml);         //更新最大值
    fa.bml=max(fa.bml,max(fa.bll,fa.brl)); 
    fa.bml=max(fa.bml,lson.brl+rson.bll); 
  
    fa.wll=lson.wll;                       //同理
    if(fa.wll==lson.len) fa.wll+=rson.wll; 
    fa.wrl=rson.wrl; 
    if(fa.wrl==rson.len) fa.wrl+=lson.wrl; 
    fa.wml=max(lson.wml,rson.wml); 
    fa.wml=max(fa.wml,max(fa.wll,fa.wrl)); 
    fa.wml=max(fa.wml,lson.wrl+rson.wll); 
} 
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le,e.ri=ri,e.len=ri-le+1,e.d=0; 
    if(le==ri) 
    { 
        scanf("%d",&e.c); 
        e.init(); 
        return; 
    } 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    pushup(id); 
} 
void pushdown(int id) 
{ 
    if(fa.d) 
    { 
        lson.d^=1; 
        rson.d^=1; 
        lson.f(),rson.f(); 
        fa.d=0; 
    } 
} 
void update(int id,int x,int y) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) 
    { 
        e.d^=1; //异或操作 
        e.f(); 
        return; 
    } 
    pushdown(id); 
    int mid=(le+ri)/2; 
    if(x<=mid) update(id*2,x,y); 
    if(y>mid)  update(id*2+1,x,y); 
    pushup(id); 
    return; 
} 
int query(int id,int x,int y) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) return e.bml; 
    pushdown(id); 
    int mid=(le+ri)/2; 
    int ret=0; 
    if(x<=mid) ret=max(ret,query(id*2,x,y)); //查询左边
    if(y>mid)  ret=max(ret,query(id*2+1,x,y)); //右边
    if(x<=mid&&y>mid) ret=max(ret,min(mid-x+1,lson.brl)+min(y-mid,rson.bll));//中间合并的一段 
    pushup(id); 
    return ret; 
} 
int main() 
{ 
    while(scanf("%d",&N)!=EOF) 
    { 
        build_tree(1,1,N); 
        scanf("%d",&M); 
        int op,x,y; 
        for(int k=1;k<=M;k++) 
        { 
            scanf("%d%d%d",&op,&x,&y); 
            if(op==1) update(1,x,y); //更新
            else printf("%d\n",query(1,x,y)); //查询 
        } 
    } 
    return 0; 
} 
View Code

poj1177-Picture(扫描线求周长)

/*
题意:求周长

解析:x轴方向来一遍扫描线,y轴方向来一遍
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e8+7; 
const double eps=1e-7; 
typedef __int64 LL; 
const int maxn=20005; 
int N,num; 
struct node 
{ 
       int L,R,H,s; 
       node(int L=0,int R=0,int H=0,int s=1) 
       :L(L),R(R),H(H),s(s){} 
       bool operator < (const node& t) const
       { 
           return H<t.H; 
       } 
}Row[maxn],Col[maxn]; 
int RV[maxn],CV[maxn]; 
struct Tree 
{ 
    int le,ri,lazy,d; 
}tree[4*maxn]; 
int ans; 
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le,e.ri=ri,e.d=-1; 
    if(le==ri) { e.d=0; return; } 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    return; 
} 
int GetAns(int a,int b,int type) 
{ 
    if(type==0) return RV[b]-RV[a]; 
    else return CV[b]-CV[a]; 
} 
void pushdown(int id) 
{ 
    Tree& fa=tree[id]; 
    Tree& lson=tree[id*2]; 
    Tree& rson=tree[id*2+1]; 
    if(fa.d!=-1) 
    { 
        lson.d=rson.d=fa.d; 
        fa.d=-1; 
    } 
} 
void pushup(int id) 
{ 
    Tree& fa=tree[id]; 
    Tree& lson=tree[id*2]; 
    Tree& rson=tree[id*2+1]; 
    if(lson.d==-1||rson.d==-1) fa.d=-1; 
    else if(lson.d!=rson.d) fa.d=-1; 
    else fa.d=lson.d; 
  
} 
void update(int id,int x,int y,int c,int type) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y&&e.d!=-1) 
    { 
        if(e.d==0&&c==1) ans+=GetAns(le,ri+1,type); 
        else if(e.d==1&&c==-1) ans+=GetAns(le,ri+1,type); 
        e.d+=c; 
        return; 
    } 
    pushdown(id); 
    int mid=(le+ri)/2; 
    if(x<=mid) update(id*2,x,y,c,type); 
    if(y>mid)  update(id*2+1,x,y,c,type); 
    pushup(id); 
    return; 
} 
int Get(node A[],int B[],int type) //type是类型,指的是行或者列
{ 
    sort(A+1,A+num+1); 
    sort(B+1,B+num+1); 
    int k=1; 
    for(int i=2;i<=num;i++) if(B[i]!=B[k]) B[++k]=B[i]; 
    build_tree(1,1,k); 
    int ret=0; 
    for(int i=1;i<=num;i++) 
    { 
        node& e=A[i]; 
        int x=lower_bound(B+1,B+k+1,e.L)-B; 
        int y=lower_bound(B+1,B+k+1,e.R)-B-1; 
        ans=0; 
        if(x>y) continue; 
        update(1,x,y,e.s,type); 
        ret+=ans; 
    } 
    return ret; 
} 
int solve() 
{ 
    int ret=0; 
    ret+=Get(Row,RV,0); //行方向
    ret+=Get(Col,CV,1); //列方向
    return ret; 
} 
int main() 
{ 
    while(scanf("%d",&N)!=EOF) 
    { 
        if(N==0) { printf("0\n"); continue; } 
        num=0; 
        for(int i=1;i<=N;i++) 
        { 
            int x1,y1,x2,y2; 
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 
            ++num; 
            Row[num]=node(x1,x2,y1,1);  //
            Col[num]=node(y1,y2,x1,1);  //
            RV[num]=x1; 
            CV[num]=y1; 
            ++num; 
            Row[num]=node(x1,x2,y2,-1); 
            Col[num]=node(y1,y2,x2,-1); 
            RV[num]=x2; 
            CV[num]=y2; 
        } 
        printf("%d\n",solve()); 
    } 
  
    return 0; 
} 
View Code

poj2777-Count Color(线段树+状态压缩)

/*
题意:给一段区间染色,颜色最多30种,查询一段区间有多少种颜色

解析:状态压缩,增加S变量,如果哪种颜色被染了,则对应的二进制位为1
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
const int maxn=100005; 
typedef __int64 LL; 
struct Tree 
{ 
    int le,ri,lazy; 
    LL S; 
}tree[4*maxn]; 
int L,T,O; 
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le,e.ri=ri,e.S=2,e.lazy=-1; //S=2代表染了1这种颜色
    if(le==ri) return; 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    return; 
} 
void pushdown(int id) 
{ 
    if(tree[id].lazy!=-1) //延迟更新
    { 
        tree[id*2].lazy=tree[id*2+1].lazy=tree[id].lazy; 
        tree[id*2].S=tree[id*2+1].S=tree[id].S; 
        tree[id].lazy=-1; 
    } 
} 
void pushup(int id) 
{ 
    tree[id].S=tree[id*2].S | tree[id*2+1].S; //或运算
} 
void update(int id,int x,int y,int c) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y){ e.lazy=c; e.S=(LL)1<<c; return; } //染c色
    pushdown(id); 
    int mid=(le+ri)/2; 
    if(x<=mid) update(id*2,x,y,c); 
    if(y>mid)  update(id*2+1,x,y,c); 
    pushup(id); 
    return; 
} 
LL query(int id,int x,int y) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) return e.S; 
    pushdown(id); 
    int mid=(le+ri)/2; 
    LL ret=0; 
    if(x<=mid) ret|=query(id*2,x,y); 
    if(y>mid)  ret|=query(id*2+1,x,y); 
    pushup(id); 
    return ret; 
} 
int main() 
{ 
    scanf("%d%d%d",&L,&T,&O); 
    char op[2]; 
    int x,y,c; 
    build_tree(1,1,L); 
    while(O--) 
    { 
        scanf("%s",op); 
        if(op[0]=='C') 
        { 
            scanf("%d%d%d",&x,&y,&c); 
            update(1,x,y,c); 
        } 
        else
        { 
            scanf("%d%d",&x,&y); 
            if(x>y) swap(x,y); 
            LL S=query(1,x,y); 
            int ans=0; 
            while(S) //计算有多少种颜色
            { 
                if(S&1) ans++;  
                S>>=1; 
            } 
            printf("%d\n",ans); 
        } 
    } 
    return 0; 
} 
View Code

poj2828-Buy Tickets(线段树查询空位)

/*
题意:排队,但是可以插队,一个人来了可以插到第i个人之后
0代表柜台,问最后的队伍顺序。

解析:一开始建树时每一段都是空的,所以大小就是区间长度,
从后面往前面插入,如果左边位置足够,则插到左边,否则右边
找到插入位置后,空位减1
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
typedef __int64 LL; 
const int maxn=200005; 
int N,ans[maxn]; 
int pos[maxn],val[maxn]; 
struct Tree 
{ 
    int le,ri; 
    int num; 
}tree[4*maxn]; 
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le,e.ri=ri; 
    e.num=ri-le+1;     //一开始都是空的
    if(le==ri) return; 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    return; 
} 
void update(int id,int p,int v) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(le==ri){ e.num--; ans[le]=v; return; } //插入进去,空间减1
    Tree& lson=tree[id*2]; 
    Tree& rson=tree[id*2+1]; 
    if(lson.num>=p) update(id*2,p,v);  //左边足够,则插到左边
    else update(id*2+1,p-lson.num,v);  //否则右边
    e.num=lson.num+rson.num;           //更新
    return; 
} 
int main() 
{ 
    while(scanf("%d",&N)!=EOF) 
    { 
        for(int i=0;i<N;i++) scanf("%d%d",&pos[i],&val[i]); //输入
        build_tree(1,0,N-1);   //建树
        for(int i=N-1;i>=0;i--) update(1,pos[i]+1,val[i]); //插入到第Pos[i]+1的位置 
        for(int i=0;i<N;i++) //输出
        { 
            if(i) printf(" "); 
            printf("%d",ans[i]); 
        } 
        printf("\n"); 
    } 
    return 0; 
} 
View Code

poj3225-Help with Intervals(线段树+区间异或)

/*
题意:给出了几种集合运算,每次操作对一段区间进行其中的一种运算
输出最后被覆盖的区间段,要注意开区间与闭区间

解析:注意一下每种运算如何修改区间的值,在线段树里再增加两个变量
d(整个区间的值),c(是否需要异或),具体细节见代码。
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
typedef __int64 LL; 
#define fa tree[id] 
#define lson tree[id*2] 
#define rson tree[id*2+1] 
#define e tree[id] 
const int maxn=140000; 
struct Tree 
{ 
    int le,ri,d,c; //d是区间的值,c代表是否需要异或
    void UpXor() 
    { 
        if(d!=-1) d^=1; //是整个连续相同的
        else c^=1; //懒惰标记异或
    } 
}tree[4*maxn]; 
void build_tree(int id,int le,int ri) 
{ 
    e.le=le,e.ri=ri,e.d=0,e.c=0; 
    if(le==ri) return; 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    return; 
} 
inline void pushdown(int id) 
{ 
    if(fa.d!=-1) 
    { 
        lson.d=rson.d=fa.d; 
        lson.c=rson.c=0; 
        fa.d=-1; 
    } 
    if(fa.c) 
    { 
       lson.UpXor(); 
       rson.UpXor(); 
       fa.c=0; 
    } 
} 
inline void Link(int id,char op) 
{ 
    if(op=='U') fa.d=1,fa.c=0;  //并集
    else if(op=='D') fa.d=0,fa.c=0; //差集S-T
    else if(op=='C'||op=='S') fa.UpXor(); //异或
} 
void update(int id,int x,int y,char op) 
{ 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) { Link(id,op); return; } 
    pushdown(id); 
    int mid=(le+ri)/2; 
    if(x<=mid) update(id*2,x,y,op); //左边可更新
    else if(op=='I'||op=='C') lson.d=lson.c=0;  //如果是交集或者是差集T-S,左边都要置为0
    if(y>mid) update(id*2+1,x,y,op);  //右边同理
    else if(op=='I'||op=='C') rson.d=rson.c=0; 
    return; 
} 
int mark[maxn]; //标记某位置是否被占
vector<pair<int,int> > ve; 
void query(int id) 
{ 
    if(e.le==e.ri) { mark[e.le]=e.d; return; } //一直压到叶子节点
    pushdown(id); 
    query(id*2); 
    query(id*2+1); 
    return; 
} 
int main() 
{ 
    char op,a,b; 
    int x,y; 
    build_tree(1,0,131070); //扩大了2倍
    while(scanf("%c %c%d,%d%c",&op,&a,&x,&y,&b)!=EOF) 
    { 
        getchar(); 
        x*=2; y*=2; //乘2
        if(a=='(') x++;  //不是实区间加1 
        if(b==')') y--; 
        if(x>y) //区间为空
        { 
            if(op=='I'||op=='C') tree[1].c=tree[1].d=0; 
            continue; 
        } 
        update(1,x,y,op); //更新 
    } 
    memset(mark,0,sizeof(mark)); 
    query(1); //整个压下去
    ve.clear(); 
    int pre=-1; 
    for(int i=0;i<=131075;i++) 
    { 
        if(mark[i]) 
        { 
            if(pre!=-1) continue; 
            pre=i; 
        } 
        else
        { 
            if(pre==-1) continue; 
            ve.push_back(make_pair(pre,i-1)); //找区间段
            pre=-1; 
        } 
    } 
    if(ve.size()==0) printf("empty set\n"); //为空
    else
    { 
        int kase=0; 
        for(int i=0;i<ve.size();i++) //输出很恶心
        { 
            int L=ve[i].first; 
            int R=ve[i].second; 
            if(kase++) printf(" "); 
            if(L%2) printf("("); 
            else printf("["); 
            printf("%d,%d",L/2,(R+1)/2); 
            if(R%2) printf(")"); 
            else printf("]"); 
        } 
        printf("\n"); 
    } 
    return 0; 
} 
View Code

poj3277-City Horizon(扫描线)

/*
题意:给出N个矩形,都在同一水平线上,求面积并

解析:裸的扫描线
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
typedef __int64 LL; 
const int maxn=80005; 
int N,num,A[maxn]; 
struct node 
{ 
    int L,R,H,s; 
    node(int L=0,int R=0,int H=0,int s=0) 
    :L(L),R(R),H(H),s(s){} 
    bool operator < (const node& t) const
    { 
        return H<t.H; 
    } 
}Nod[maxn]; 
struct Tree 
{ 
    int le,ri,lazy; 
    int sum; 
}tree[4*maxn]; 
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le,e.ri=ri,e.lazy=0,e.sum=0; 
    if(le==ri) return; 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    return; 
} 
void pushup(int id) 
{ 
    Tree& fa=tree[id]; 
    Tree& lson=tree[id*2]; 
    Tree& rson=tree[id*2+1]; 
    if(fa.lazy) fa.sum=A[fa.ri+1]-A[fa.le]; 
    else if(fa.le==fa.ri) fa.sum=0; 
    else fa.sum=lson.sum+rson.sum; 
} 
void update(int id,int x,int y,int c) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) 
    { 
        e.lazy+=c; 
        pushup(id); 
        return; 
    } 
    int mid=(le+ri)/2; 
    if(x<=mid) update(id*2,x,y,c); 
    if(y>mid)  update(id*2+1,x,y,c); 
    pushup(id); 
    return; 
} 
LL solve() 
{ 
    LL ret=0; 
    sort(Nod+1,Nod+num+1); 
    sort(A+1,A+num+1); 
    int k=1; 
    for(int i=2;i<=num;i++) if(A[i]!=A[k]) A[++k]=A[i]; 
    build_tree(1,1,k); 
    for(int i=1;i<num;i++) 
    { 
        node& t=Nod[i]; 
        int x=lower_bound(A+1,A+k+1,t.L)-A; 
        int y=lower_bound(A+1,A+k+1,t.R)-A-1; 
        update(1,x,y,t.s); 
        ret+=(LL)tree[1].sum*((LL)Nod[i+1].H-Nod[i].H); 
    } 
    return ret; 
} 
int main() 
{ 
    while(scanf("%d",&N)!=EOF) 
    { 
        num=0; 
        int a,b,h; 
        for(int i=1;i<=N;i++) 
        { 
            scanf("%d%d%d",&a,&b,&h); 
            Nod[++num]=node(a,b,0,1); 
            A[num]=a; 
            Nod[++num]=node(a,b,h,-1); 
            A[num]=b; 
        } 
        LL ans=solve(); 
        printf("%I64d\n",ans); 
    } 
    return 0; 
} 
View Code

poj3368-Frequent values(线段树区间合并)

/*
题意:给出一组非递减的数,每次查询一段区间内出现次数最多的数的个数

解析:因为是非递减的,而且也不能更改,所以相同的数是连在一起的,
考虑用线段树区间合并记录连续的最大长度。具体细节见代码。
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
typedef __int64 LL; 
const int maxn=100005; 
#define fa tree[id] 
#define lson tree[id*2] 
#define rson tree[id*2+1] 
int N,Q; 
struct Tree 
{ 
    int le,ri,len; 
    int ll,rl,ml; //左边连续长度,右边连续长度,最大连续长度
    int lv,rv; //左端点值,右端点值
}tree[4*maxn]; 
void pushup(int id) 
{ 
    fa.ll=lson.ll; 
    if(fa.ll==lson.len&&lson.rv==rson.lv) fa.ll+=rson.ll; //延伸到右边去
    fa.rl=rson.rl; 
    if(fa.rl==rson.len&&lson.rv==rson.lv) fa.rl+=lson.rl; //延伸到左边去
    fa.ml=max(lson.ml,rson.ml); 
    if(lson.rv==rson.lv) fa.ml=max(fa.ml,lson.rl+rson.ll); //取最大值
    fa.lv=lson.lv; //左右端点的值
    fa.rv=rson.rv; 
} 
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le, e.ri=ri, e.len=ri-le+1; 
    if(le==ri) 
    { 
        scanf("%d",&e.lv); 
        e.rv=e.lv; 
        e.ll=e.rl=e.ml=1; //叶子节点为1
        return; 
    } 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    pushup(id); 
    return; 
} 
int query(int id,int x,int y) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) return e.ml; 
    int mid=(le+ri)/2; 
    int ret=0; 
    if(x<=mid) ret=max(ret,query(id*2,x,y)); //左边
    if(y>mid)  ret=max(ret,query(id*2+1,x,y)); //右边
    if(x<=mid&&y>mid) 
    { 
        if(lson.rv==rson.lv) 
            ret=max(ret,min(lson.rl,mid-x+1)+min(rson.ll,y-mid)); //中间 
    } 
    return ret; 
} 
int main() 
{ 
    while(true) 
    { 
        scanf("%d",&N); 
        if(!N) break; 
        scanf("%d",&Q); 
        build_tree(1,1,N); 
        int x,y; 
        for(int i=1;i<=Q;i++) 
        { 
            scanf("%d%d",&x,&y); 
            printf("%d\n",query(1,x,y)); 
        } 
    } 
    return 0; 
}
View Code

zoj1610-Count the Colors(线段树区间覆盖)

/*
题意:给区间染色,最后求每种可见的颜色有多少段

解析:区间覆盖问题,最后整个压下去,统计一下个数即可。
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
const int INF=1e9+7; 
const double eps=1e-7; 
  
const int maxn=8005; 
struct Tree 
{ 
    int le,ri,lazy; 
}tree[4*maxn]; 
int N; 
int color[maxn],mark[maxn]; //mark标记颜色,color记录个数
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le,e.ri=ri,e.lazy=-1; 
    if(le==ri) return; 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    return; 
} 
void pushdown(int id) 
{ 
    Tree& fa=tree[id]; 
    Tree& lson=tree[id*2]; 
    Tree& rson=tree[id*2+1]; 
    if(fa.lazy!=-1) 
    { 
        lson.lazy=rson.lazy=fa.lazy; 
        fa.lazy=-1; 
    } 
} 
void update(int id,int x,int y,int c) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) 
    { 
        e.lazy=c; 
        if(le==ri) mark[le]=c; //叶子节点
        return; 
    } 
    pushdown(id); 
    int mid=(le+ri)/2; 
    if(x<=mid) update(id*2,x,y,c); 
    if(y>mid)  update(id*2+1,x,y,c); 
    return; 
} 
void query(int id) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri,lazy=e.lazy; 
    if(le==ri) 
    { 
        mark[le]=lazy; //一直到叶子节点
        return; 
    } 
    pushdown(id); 
    query(id*2); 
    query(id*2+1); 
    return; 
} 
int main() 
{ 
    while(scanf("%d",&N)!=EOF) 
    { 
        build_tree(1,1,8000); 
        int x,y,c; 
        memset(mark,-1,sizeof(mark)); 
        for(int i=1;i<=N;i++) 
        { 
            scanf("%d%d%d",&x,&y,&c); 
            update(1,x+1,y,c); 
        } 
        query(1); 
        memset(color,0,sizeof(color)); 
        for(int i=1;i<=8000;i++) //统计个数
            if(mark[i]!=mark[i-1]) color[mark[i]]++; 
        for(int i=0;i<=8000;i++) //不为0可见
            if(color[i]) printf("%d %d\n",i,color[i]); 
        printf("\n"); 
    } 
    return 0; 
} 
View Code

zoj2706-Thermal Death of the Universe(线段树成段更新)

/*
题意:更新一段区间,把这段区间的数全部置为其平均数
如果这段区间的和小于等于总和则向上取整,否则向下取整

解析:线段树成段更新,注意一下题目的要求即可。
*/
#include<cstdio> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<sstream> 
#include<utility> 
#include<iterator> 
using namespace std; 
typedef long long LL; 
const LL INF=1e15+7; 
const double eps=1e-7; 
#define fa tree[id] 
#define lson tree[id*2] 
#define rson tree[id*2+1] 
const int maxn=30005; 
struct Tree 
{ 
    int le,ri; 
    LL sum,d; 
    void init(){ sum=d*(ri-le+1); } 
}tree[4*maxn]; 
int N,M; 
LL mark[maxn]; 
void pushup(int id) 
{ 
    fa.sum=lson.sum+rson.sum; 
} 
void build_tree(int id,int le,int ri) 
{ 
    Tree& e=tree[id]; 
    e.le=le,e.ri=ri,e.d=-INF; 
    if(le==ri) 
    { 
        scanf("%lld",&e.sum); 
        e.d=e.sum; 
        return; 
    } 
    int mid=(le+ri)/2; 
    build_tree(id*2,le,mid); 
    build_tree(id*2+1,mid+1,ri); 
    pushup(id); 
    return; 
} 
void pushdown(int id) 
{ 
    if(fa.d!=-INF) 
    { 
        lson.d=rson.d=fa.d; 
        lson.init(); rson.init(); 
        fa.d=-INF; 
    } 
} 
void update(int id,int x,int y,LL c) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) 
    { 
        e.d=c; 
        e.init(); 
        return; 
    } 
    pushdown(id); 
    int mid=(le+ri)/2; 
    if(x<=mid) update(id*2,x,y,c); 
    if(y>mid) update(id*2+1,x,y,c); 
    pushup(id); 
    return; 
} 
LL query(int id,int x,int y) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(x<=le&&ri<=y) return e.sum; 
    pushdown(id); 
    int mid=(le+ri)/2; 
    LL ret=0; 
    if(x<=mid) ret+=query(id*2,x,y); 
    if(y>mid)  ret+=query(id*2+1,x,y); 
    pushup(id); 
    return ret; 
} 
void GetMark(int id) 
{ 
    Tree& e=tree[id]; 
    int le=e.le,ri=e.ri; 
    if(le==ri){ mark[le]=e.sum; return; } 
    pushdown(id); 
    GetMark(id*2); 
    GetMark(id*2+1); 
    return; 
} 
int main() 
{ 
    while(scanf("%d%d",&N,&M)!=EOF) 
    { 
        build_tree(1,1,N); 
        LL org=tree[1].sum; 
        int x,y; 
        for(int k=1;k<=M;k++) 
        { 
            scanf("%d%d",&x,&y); 
            LL S=query(1,x,y); 
            LL L=y-x+1; 
            if(tree[1].sum<=org) 
            { 
                if(S<0) update(1,x,y,-(-S/L)); 
                else  update(1,x,y,(S+L-1)/L); 
            } 
            else
            { 
                if(S<0) update(1,x,y,-((-S+L-1)/L)); 
                else update(1,x,y,S/L); 
            } 
        } 
        GetMark(1); 
        int kase=0; 
        for(int i=1;i<=N;i++) 
        { 
            if(kase++) printf(" "); 
            printf("%lld",mark[i]); 
        } 
        printf("\n\n"); 
    } 
    return 0; 
} 
View Code

 

posted @ 2016-07-18 20:17  wust_ouyangli  阅读(420)  评论(0编辑  收藏  举报