线段树专题(二)

马不停蹄,马不停蹄,才写完上一部分,没有时间休息,又要开始下一部分了。这部分主要是线段树区间更新的难题和区间合并的一些题目,最后最困难的扫描线算法应该会出现在第三部分。



第一题 ZOJ 1610

分析:首先声明一点这道题我没有AC,当然不是因为我不会,而是因为坑人的ZOJ又爆炸了,交不了代码。所以万一我的代码出了问题,你们不准打我,思路是肯定没有问题的。

其实这道题不算难题啦,只是因为我的失误,错把它分到第二部分了,唉,就当热身。

给你N个气球,在区间端上刷颜色,最后让你求每个颜色的段数。那么还是老套路,区间更新+最后查询一次。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          8000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>=‘0‘&&c<=‘9‘)||c==‘-‘))c=getchar();
    bool flag=1;
    if(c==‘-‘)
    {
        flag=0;
        c=getchar();
    }
    while(c<=‘9‘&&c>=‘0‘)
    {
        x=x*10+c-‘0‘;
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

int col[maxn<<2];
int vis[maxn];
int anw[maxn];
void build(int l,int r,int rt){
    col[rt]=-1;
    if(l==r){
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void pushdown(int rt){
    if(col[rt]!=-1){
        col[rt<<1]=col[rt<<1|1]=col[rt];
        col[rt]=-1;
    }
}
void update(int l,int r,int rt,int L,int R,int p){
    if(L<=l&&r<=R){
        col[rt]=p;
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)update(lson,L,R,p);
    if(R>m) update(rson,L,R,p);
}
void query(int l,int r,int rt){
    if(col[rt]!=-1){
        for(int i=l;i<=r;i++)
            anw[i]=col[rt];
        return ;
    }
    if(l==r){
        anw[l]=-1;
        return ;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    query(lson);
    query(rson);
}
int main(){
    //freopen("d:\\acm\\in.in","r",stdin);
    int n;
    while(~scanf("%d",&n)){
        build(1,8000,1);
        while(n--){
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            a++;
            update(1,8000,1,a,b,c);
        }
        query(1,8000,1);
        clr(vis,0);
        if(anw[1]!=-1)vis[anw[1]]++;
        for(int i=2;i<=8000;i++)
            if(anw[i]!=-1&&anw[i]!=anw[i-1])
                vis[anw[i]]++;
        for(int i=0;i<=8000;i++)
            if(vis[i])
                printf("%d %d\n",i,vis[i]);
        puts("");
    }
    return 0;
}


第二题 POJ 3264

分析:第二题也不难。是求区间最大值与最小值的差+区间更新。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          50000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>=‘0‘&&c<=‘9‘)||c==‘-‘))c=getchar();
    bool flag=1;
    if(c==‘-‘)
    {
        flag=0;
        c=getchar();
    }
    while(c<=‘9‘&&c>=‘0‘)
    {
        x=x*10+c-‘0‘;
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

int minn[maxn<<2];
int maxx[maxn<<2];
void pushup(int rt){
    minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
    maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);
}
void build(int l,int r,int rt){
    if(l==r){
        scanf("%d",&minn[rt]);
        maxx[rt]=minn[rt];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
int query(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R){
        return minn[rt];
    }
    int ans=inf;
    int m=(l+r)>>1;
    if(L<=m)ans=min(ans,query(lson,L,R));
    if(R>m) ans=min(ans,query(rson,L,R));
    return ans;
}
int query1(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R){
        return maxx[rt];
    }
    int ans=0;
    int m=(l+r)>>1;
    if(L<=m)ans=max(ans,query1(lson,L,R));
    if(R>m) ans=max(ans,query1(rson,L,R));
    return ans;
}
int main(){
    //freopen("d:\\acm\\in.in","r",stdin);
    int n,q;
    while(~scanf("%d %d",&n,&q)){
        build(1,n,1);
        while(q--){
            int a,b;
            scanf("%d %d",&a,&b);
            printf("%d\n",query1(1,n,1,a,b)-query(1,n,1,a,b));
        }
    }
    return 0;
}


第三题 POJ 2777

分析:这是一道很简单的区间染色题目。如果写得太随意,可能会超时!

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          100000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>=‘0‘&&c<=‘9‘)||c==‘-‘))c=getchar();
    bool flag=1;
    if(c==‘-‘)
    {
        flag=0;
        c=getchar();
    }
    while(c<=‘9‘&&c>=‘0‘)
    {
        x=x*10+c-‘0‘;
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

int col[maxn<<2];
int ans;
bool vis[maxn];
void pushdown(int rt){
    if(col[rt]){
        col[rt<<1]=col[rt<<1|1]=col[rt];
        col[rt]=0;
    }
}
void update(int l,int r,int rt,int L,int R,int p){
    if(L<=l&&r<=R){
        col[rt]=p;
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)update(lson,L,R,p);
    if(R>m) update(rson,L,R,p);
}
void query(int l,int r,int rt,int L,int R){
    if(col[rt]){
        if(!vis[col[rt]]){
            ans++;
            vis[col[rt]]=true;
        }
        return;
    }
    if(l==r)return;
    int m=(l+r)>>1;
    if(L<=m)query(lson,L,R);
    if(R>m) query(rson,L,R);
}
int main(){
    //freopen("d:\\acm\\in.in","r",stdin);
    int n,t,p;
    while(~scanf("%d %d %d",&n,&t,&p)){
        col[1]=1;
        while(p--){
            char op[5];
            int a,b,c;
            scanf("%s %d %d",op,&a,&b);
            if(a>b)swap(a,b);
            if(op[0]==‘C‘){
                scanf("%d",&c);
                update(1,n,1,a,b,c);
            }
            else {
                ans=0;
                for(int i=1;i<=t;i++)
                    vis[i]=false;
                query(1,n,1,a,b);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}


第四题 HDU 4027

分析:给你N个数,然后给你Q次询问,每次询问以t,a,b的形式出现,如果t为0表示更新,把从a到b之间的数全部开根取整,如果t为1表示查询,输入从a到b之间的数的和。

刚开始想我觉得这肯定是一个求区间和+区间更新的题目。然后细细地想了想,发现不是很好写,有点小问题。区间更新的时候,很难保证一边自上而下更新的时候,还可以维护中间和的值,甚至上是根本没有办法维护的,所以这条道路被我们给舍弃了。然后,我们回过头来细细想一下开方这个有点独特的运算,一般一个数多次开方后就一定会成为1,而且再来多少次开方都不会变化。我们立刻想到可以利用这个特性,检查这个区间是否还需要开方(是不是区间上的数都变成1了),如果不要的话,那么直接不用管这个区间了,这将节省大量的时间复杂度。那么我们完全可以将区间更新退化为点更新,大量的1区间将会自动优化这个算法的复杂度。之后就是很简单的区间求和,这应该难不倒读者。

哦,对了,注意这题目的坑点,a可能大于b,这时候应该将a与b的值交换。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          100000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>=‘0‘&&c<=‘9‘)||c==‘-‘))c=getchar();
    bool flag=1;
    if(c==‘-‘)
    {
        flag=0;
        c=getchar();
    }
    while(c<=‘9‘&&c>=‘0‘)
    {
        x=x*10+c-‘0‘;
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

ll sum[maxn<<2];
void pushup(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt){
    if(l==r){
        scanf("%lld",&sum[rt]);
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int l,int r,int rt,int L,int R){
    if(sum[rt]==(r-l+1)){
        return;
    }
    if(l==r){
        sum[rt]=(int)sqrt(sum[rt]*1.0);
        return;
    }
    int m=(l+r)>>1;
    if(L<=m)update(lson,L,R);
    if(R>m)update(rson,L,R);
    pushup(rt);
}
ll query(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R){
        return sum[rt];
    }
    int m=(l+r)>>1;
    ll ans=0;
    if(L<=m)ans+=query(lson,L,R);
    if(R>m) ans+=query(rson,L,R);
    return ans;
}
int main(){
    //freopen("d:\\acm\\in.in","r",stdin);
    int n,cas=1;
    while(~scanf("%d",&n)){
        printf("Case #%d:\n",cas++);
        build(1,n,1);
        int q;
        scanf("%d",&q);
        while(q--){
            int t,a,b;
            scanf("%d %d %d",&t,&a,&b);
            if(a>b)swap(a,b);
            if(t==1)printf("%lld\n",query(1,n,1,a,b));
            else update(1,n,1,a,b);
        }
        puts("");
    }
    return 0;
}


第五题 POJ 3225

分析:这道题目太难,实在是太难。但是这也是一道非常非常有思考价值的题目,强烈推荐认真做。

首先,题目意思就不说了,为什么呢?因为这道题有中文题意,POJ上去切换语言。

说实话,一开始我没有理解样例,以为应该算出来是空集合。然后看了discuss才知道,这里面不仅计算整数,小数和无理数也包括,集合的操作是针对整个实数范围来说的。

那么我们很容易的就可以想到,用偶数来表示整数,用奇数来表示整数之间的小数和无理数。因为很显然,将范围乘以2,就形成一种一一对应的映射关系。

然后,考虑怎么实现当前集合的维护。我们可以使用0表示这个数不在集合中,用1表示这个数在集合中,那么我们还需要-1表示当前无法判断,需要向下一层才能知道。

然后我们对每种操作进行分析:

U:就是把区间[l,r]全部置为1

I:就是把[0,l)和(r,MAXN]置为0

D:就是把区间[l,r]全部置为1

C:就是把[0,l)和(r,MAXN]置为0,再把区间[l,r]全部取反

S:就是把区间[l,r]全部取反

我最先没有想到要将异或单独出一个标记(后来也没有想到,是看了大神的代码才知道的),我一开始是将两种操作统一,直接将异或操作也是算作一种区间更新,与置01同地位。虽然不是那种退化成单点更新的模式,但是复杂度还是很高,不管怎么优化都TLE了。

回归正解,当一个区间被置1或者0,那么之前的异或标记就没有意义;当一个区间被取反,那么要么直接修改覆盖值,要么记成异或标记。得出结论:异或标记只能严格在覆盖值的上面,和覆盖值同层或者低层的异或标记根本没有意义,也就是覆盖值和异或标记不可能同时存在于同一层。那么我们将异或标记和覆盖值延伸时,就应该优先处理覆盖值,而且如果处理覆盖值,那么就不需要处理异或标记。只有在当前覆盖值为-1,表示无法确定下面的值,而且异或标记还存在的情况下,才会去处理异或标记。处理异或标记的时候,优先直接在覆盖值上处理,如果覆盖值为-1时,才为下一层记下标记。

对于代码稍微说明一下,update表示置1或置0操作,uodata表示取反操作,显然它们是可以写在一起的,但是我不想改了。还有,最后得到了集合的01序列,我因为不想写那种麻烦的遍历,所以加了个队列判断01和10的地点,可能有点慢,但能够少动不少脑子,所以也不想改了。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          131070+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>=‘0‘&&c<=‘9‘)||c==‘-‘))c=getchar();
    bool flag=1;
    if(c==‘-‘)
    {
        flag=0;
        c=getchar();
    }
    while(c<=‘9‘&&c>=‘0‘)
    {
        x=x*10+c-‘0‘;
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

const int len = 131070;
int Xor[maxn<<2];
int col[maxn<<2];
int anw[maxn];
void cal(int rt){
    if(col[rt]!=-1)col[rt]^=1;
    else Xor[rt]^=1;
}
void pushdown(int rt){
    if(col[rt]!=-1){
        col[rt<<1]=col[rt<<1|1]=col[rt];
        Xor[rt]=0;
        col[rt]=-1;
    }
    else if(Xor[rt]){
        cal(rt<<1);
        cal(rt<<1|1);
        Xor[rt]=0;
    }
}
void update(int l,int r,int rt,int L,int R,int p){
    if(L<=l&&r<=R){
        col[rt]=p;
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)update(lson,L,R,p);
    if(R>m) update(rson,L,R,p);
}
void updata(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R){
        cal(rt);
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)updata(lson,L,R);
    if(R>m) updata(rson,L,R);
}
void query(int l,int r,int rt){
    if(col[rt]!=-1){
        if(col[rt]){
            for(int i=l;i<=r;i++)
                anw[i]=col[rt];
        }
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    query(lson);
    query(rson);
}
int main(){
    //freopen("d:\\acm\\in.in","r",stdin);
    int a,b;
    char c,d,op;
    col[1]=Xor[1]=0;
    while(~scanf("%c %c%d,%d%c\n",&op,&c,&a,&b,&d)){
        a<<=1;if(c==‘(‘)a++;
        b<<=1;if(d==‘)‘)b--;
        if(op==‘U‘)update(0,len,1,a,b,1);
        else if(op==‘I‘){
            if(a!=0)update(0,len,1,0,a-1,0);
            if(b!=len)update(0,len,1,b+1,len,0);
        }
        else if(op==‘D‘)update(0,len,1,a,b,0);
        else if(op==‘C‘){
            if(a!=0)update(0,len,1,0,a-1,0);
            if(b!=len)update(0,len,1,b+1,len,0);
            updata(0,len,1,a,b);
        }
        else updata(0,len,1,a,b);
        /*query(0,len,1);
        for(int i=0;i<=10;i++)
            cout<<anw[i]<<" ";
        cout<<endl;*/
    }
    query(0,len,1);
    queue<int>que;
    if(anw[0])que.push(0);
    for(int i=1;i<=len;i++)
        if(anw[i]&&!anw[i-1])que.push(i);
        else if(anw[i-1]&&!anw[i])que.push(i-1);
    if(anw[len])que.push(len);
    if(que.empty())puts("empty set");
    else {
        int cnt=0;
        while(!que.empty()){
            int a=que.front();
            que.pop();
            int b=que.front();
            que.pop();
            if(cnt)putchar(‘ ‘);
            cnt=1;
            if(a&1)printf("(%d,",a/2);
            else printf("[%d,",a/2);
            if(b&1)printf("%d)",(b+1)/2);
            else printf("%d]",b/2);
        }
        putchar(‘\n‘);
    }
    return 0;
}


第六题 POJ 1436

分析:这道题目题意特别难理解,我有段时间就是认为样例是错的(现在还是觉得题目描述不好)。为了不影响读者的思路,我就不给出题意了,请大家自行百度。

这道题应该是难在不知道怎么做,怎么求线段之间的关系。首先给你线段的坐标,这种关系是非常抽象的,必须将它们变成两两线段之间是否存在视野可见的关系(给出一个表格,类似邻接矩阵)。对于这个表格,使用暴力搜索方法,或者用矩阵相乘的思路,都是可以的,复杂度差不多。

然后问题转化为怎么求解两两线段之间的视野可见关系。那么我们在图上画一下,发现从y轴的方向上看,正好像一个区间染色的问题,在某一条线段染色之前,在它将要染色的区域查询。这时候所能看到的线段就是与它具有视野可见关系的线段,可以在表格中记录,然后进行更新(即染色)操作。

还有一个注意点,根据样例可知,这两条线段之间可见,是包括整数点的,结合以前的经验,我们需要把范围乘以2。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          16000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>=‘0‘&&c<=‘9‘)||c==‘-‘))c=getchar();
    bool flag=1;
    if(c==‘-‘)
    {
        flag=0;
        c=getchar();
    }
    while(c<=‘9‘&&c>=‘0‘)
    {
        x=x*10+c-‘0‘;
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

bool vis[8010][8010];
const int len = 16000;
struct edge{
    int l,r;
    int x;
    friend bool operator < (const edge& A,const edge& B){
        return A.x<B.x;
    }
}dat[maxn];
int col[maxn<<2];
void build(int l,int r,int rt){
    col[rt]=0;
    if(l==r){
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void query(int l,int r,int rt,int L,int R,int x){
    if(col[rt]){
        vis[x][col[rt]]=vis[col[rt]][x]=true;
        return;
    }
    if(l==r)return;
    int m=(l+r)>>1;
    if(L<=m)query(lson,L,R,x);
    if(R>m)query(rson,L,R,x);
}
void pushdown(int rt){
    if(col[rt]){
        col[rt<<1]=col[rt<<1|1]=col[rt];
        col[rt]=0;
    }
}
void update(int l,int r,int rt,int L,int R,int x){
    if(L<=l&&r<=R){
        col[rt]=x;
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)update(lson,L,R,x);
    if(R>m)update(rson,L,R,x);
}
int main(){
    //freopen("d:\\acm\\in.in","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d %d %d",&dat[i].l,&dat[i].r,&dat[i].x);
        sort(dat,dat+n);
        build(0,len,1);
        clr(vis,false);
        for(int i=0;i<n;i++){
            query(0,len,1,dat[i].l<<1,dat[i].r<<1,i+1);
            update(0,len,1,dat[i].l<<1,dat[i].r<<1,i+1);
        }

        /*for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                cout<<vis[i][j]<<" ";
            cout<<endl;
        }*/

        int ans=0;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                if(vis[i][j]){
                    for(int k=j+1;k<=n;k++)
                        if(vis[j][k]&&vis[i][k])
                            ans++;
                }
        cout<<ans<<endl;
    }
    return 0;
}


第七题 POJ 2991

分析:这道题题意也太麻烦,自己百度去吧。

这道并没有想象的那么难,但是也坑了我好久,主要是我旋转公式不记得了。而且我天生与英语有仇,TMD读了好多遍题意,还是读错了,把转到多少度理解成转了多少度,然后各种WA。

首先,我是想了好久并且测试了几组数据之后才敢把线段当作向量来使。这道题将每个线段看成一个向量,最后的尾端的坐标值看成所有向量的矢量和,我们当然清楚所有向量的矢量和就是这些向量相对于原点的坐标值之和。那么我们可以将x坐标和y坐标分开来看,更新的时候需要一起,但是求和的时候就是各自求和了。那么,这道题目就是转换成了非常一般的求区间和+区间更新的题目,稍微有点不同的是这里有两个项目需要求和,而且这两个项目不是像最小值和最大值一样没什么关系,而是有密切关系的,在同一层需要同时更新的。

注意一下,这里的旋转是指旋转到多大的角度,而不是在前面的基础上再旋转了多大的角度。所以需要维护一下,以前的角度,这样可以知道每次需要旋转多少角度,方便使用向量旋转公式。哦,对了,最重要的旋转公式没有给出来,自己百度把。

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          10000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>=‘0‘&&c<=‘9‘)||c==‘-‘))c=getchar();
    bool flag=1;
    if(c==‘-‘)
    {
        flag=0;
        c=getchar();
    }
    while(c<=‘9‘&&c>=‘0‘)
    {
        x=x*10+c-‘0‘;
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------

int col[maxn<<2];
double X[maxn<<2],Y[maxn<<2];
int dep[maxn];
void pushup(int rt){
    X[rt]=X[rt<<1]+X[rt<<1|1];
    Y[rt]=Y[rt<<1]+Y[rt<<1|1];
}
void build(int l,int r,int rt){
    col[rt]=0;
    if(l==r){
        X[rt]=0;
        scanf("%lf",&Y[rt]);
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void cal(double& x,double& y,int p){
    double ang=p*pi/180.0;
    double tx=x*cos(ang)-y*sin(ang);
    double ty=x*sin(ang)+y*cos(ang);
    x=tx;
    y=ty;
}
void pushdown(int rt){
    if(col[rt]){
        col[rt<<1]+=col[rt];
        col[rt<<1|1]+=col[rt];
        cal(X[rt<<1],Y[rt<<1],col[rt]);
        cal(X[rt<<1|1],Y[rt<<1|1],col[rt]);
        col[rt]=0;
    }
}
void update(int l,int r,int rt,int L,int R,int p){
    if(L<=l&&r<=R){
        cal(X[rt],Y[rt],p);
        col[rt]+=p;
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)update(lson,L,R,p);
    if(R>m) update(rson,L,R,p);
    pushup(rt);
}
int main(){
    //freopen("d:\\acm\\in.in","r",stdin);
    int n,m,cnt=0;
    while(~scanf("%d %d",&n,&m)){
        if(cnt)putchar(‘\n‘);
        cnt=1;
        build(1,n,1);
        for(int i=1;i<=n;i++)
            dep[i]=180;
        while(m--){
            int p,h;
            scanf("%d %d",&p,&h);
            update(1,n,1,p+1,n,h-dep[p]);
            dep[p]=h;
            printf("%.2lf %.2lf\n",X[1],Y[1]);
        }
    }
    return 0;
}


好像纯的区间更新难题就这么多了,写完了,花了两天。

时间: 2024-10-09 23:15:55

线段树专题(二)的相关文章

hdu 2795 线段树(二维问题一维化)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10961    Accepted Submission(s): 4863 Problem Description At the entrance to the university, there is a huge rectangular billboard of s

论线段树:二

<论线段树> ——线段树精细讲解第二篇   ——Yeasion_Nein出品 ><论线段树:一> ><论线段树:二> 在上一节中,我们大概了解了线段树的运算机制以及基本的代码运行 ,在这一节,我们主要针对一个例题进行更深层次的讲解. 首先来看一道题.(题目原链接:线段树2 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第

vj线段树专题

vj线段树专题题解 单点更新模板 void build(int x,int l,int r){//sum[x]控制l-r区域 if(l==r){Sum[x]=num[l];return ;} int mid=l+((r-l)>>1); build(x<<1,l,mid); build(x<<1|1,mid+1,r); Sum[x]=Sum[x<<1]+Sum[x<<1|1]; } void add(int a,int b,int l,int r,

[kuangbin]带你飞之&#39;线段树&#39;专题(未完成)

// 带飞网址 https://vjudge.net/article/187 专题七 线段树 HDU 1166 敌兵布阵HDU 1754 I Hate It√ POJ 3468 A Simple Problem with IntegersPOJ 2528 Mayor's postersHDU 1698 Just a HookZOJ 1610 Count the ColorsPOJ 3264 Balanced LineupHDU 4027 Can you answer these queries?

线段树(二)

转自:http://blog.csdn.net/liujian20150808/article/details/51137749 1.线段树的定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b].因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度. 举例描述: 因此有了以上对线段树的定

spoj GSS线段树以及二维树状数组合集

T1 维护lmax 向左延伸的最大值,rmax同理,sum区间和,ans答案. 转移见operator + #include<bits/stdc++.h> #define mid (l+(r-l)/2) #define ls (rt<<1) #define rs (rt<<1|1) #define int long long using namespace std; const int N =(int)1e5+10; struct TREE { int lef,rig,

线段树专题(一)

Acmer可怜啊,根本没有休息,昨天才刚刚完成了矩阵专题,今天又要开线段树专题了.唉,等我以后月薪15K的时候,我要好好享受人生......呃,扯远了.线段树是一个非常重要的数据结构,以前就学习过,但是没有系统的刷过难题,这次我决定将kuangbin先生的专题和NotOnlySuccess大神的专题一起刷掉.因为题目多又难,所以分成几个部分(最多三个把). 对于线段树的话,主要是理解它的树形结构吧,推荐和树状数组一起学习.似乎树状数组就是线段树的退化,树状数组节约了差不多一半的空间,但是必须满足

[题解]线段树专题测试2017.1.21

很单纯的一道线段树题.稍微改一下pushDown()就行了. Code(线段树模板竟然没超100行) 1 #include<iostream> 2 #include<sstream> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<cctype> 8 #include<queue> 9

非递归线段树专题

学习了自底向上的非递归线段树,深感精妙!! 大牛的博客:http://blog.csdn.net/zearot/article/details/48299459 张坤玮---统计的力量 The Union of k-Segments CodeForces - 612D 题意:求被覆盖k次及以上的点或者线段. 看到别人直接用扫描线写的,更方便一些. 不过拿来练习线段树也不错. 1 #include <bits/stdc++.h> 2 using namespace std; 3 const in