• 【题解】L 国的战斗续之多路出击 [P2129]


    【题解】L 国的战斗续之多路出击 [P2129]

    传送门: (L) 国的战斗续之多路出击 ([P2129])

    【题目描述】

    给出 (n) 个坐标,(m) 个指令,指令处理顺序应是从后往前

    求最终的 (n) 个坐标。

    【输入】

    第一行两个整数 (n,m)

    接下来 (n) 行,每行两个整数 (x_i,y_i) 表示第 (i) 个坐标。

    然后 (m) 行,每行首先一个字符 (C)

    ((1).)(C)( ext{'m'}),则紧跟两个整数 (p,q),要求把所有坐标 ((x_i,y_i)) 变为 ((x_i+p,y_i+q))

    ((2).)(C)( ext{'x'}),则把所有坐标从 ((xi,yi)) 变为 ((-xi,yi))

    ((3).)(C)( ext{'y'}),则把所有坐标从 ((xi,yi)) 变为 ((xi,-yi))

    【输出】

    【样例】

    样例输入:
    3 3
    0 0
    4 -3
    6 7
    x
    m -1 2
    y
    
    样例输出:
    1 2
    -3 5
    -5 -5
    

    【数据范围】

    (30 \%:) (1 leqslant n,m leqslant 1000)

    (100 \%:) (1 leqslant n,m leqslant 5*10^5)


    【分析】

    大佬们都写的是矩阵乘法或者模拟,向我这种不会矩阵和膜您的蒟蒻就只能写线段树了 ( ext{QAQ}) (好像是第一个用这种奇葩方法的?)。

    区间加,区间乘的模板,但因为是单调查询,而且没有取模这种鬼畜操作,比【模板】线段树 (2)维护序列 要简单得多。

    维护一个乘法标记 (mul) 和加法标记 (add),区间加时就直接更新 (add),区间乘 (v) 就先让 (mul)(add) 都乘以 (v)

    下传标记时先传 (mul) 再传 (add)

    其他的就直接照着题目模拟就可以了。

    坑点:(m) 个指令要倒着处理。

    【Code】

    #include<cstdio>
    #define Re register int
    #define pl (p<<1)//左儿子
    #define pr (p<<1|1)//右儿子
    #define mid (L+R>>1)
    #define pa tr[p].add//加法标记
    #define pm tr[p].mul//乘法标记
    const int N=5e5+5;
    int n,x,y,T,a[N],b[N];
    inline void in(Re &x){
        Re f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    struct Segment_Tree{
        struct QAQ{int l,r,ans,add,mul;}tr[N<<2];
        inline void updata_add(Re p,Re v){
            if(tr[p].l==tr[p].r)tr[p].ans+=v;//只需要更新叶子节点
            pa+=v;//但标记必须下传
        }
        inline void updata_mul(Re p,Re v){
            if(tr[p].l==tr[p].r)tr[p].ans*=v;//同上
            pm*=v,pa*=v;
        }
        inline void pushdown(Re p){//先下传乘法标记,再下传加法标记
            if(pm!=1)updata_mul(pl,pm),updata_mul(pr,pm),pm=1;//这里乘法标记也要初始化为1
            if(pa)updata_add(pl,pa),updata_add(pr,pa),pa=0;
        }
        inline void build(Re p,Re L,Re R){//初始化建树
            tr[p].l=L,tr[p].r=R,pm=1;//乘标记要初始化为1
            if(L==R){tr[p].ans=a[L];return;}
            build(pl,L,mid),build(pr,mid+1,R);
        }
        inline void change_add(Re p,Re l,Re r,Re v){//区间加
            Re L=tr[p].l,R=tr[p].r;
            if(l<=L&&R<=r){updata_add(p,v);return;}
            pushdown(p);
            if(l<=mid)change_add(pl,l,r,v);
            if(r>mid)change_add(pr,l,r,v);
        }
        inline void change_mul(Re p,Re l,Re r,Re v){//区间乘
            Re L=tr[p].l,R=tr[p].r;
            if(l<=L&&R<=r){updata_mul(p,v);return;}
            pushdown(p);
            if(l<=mid)change_mul(pl,l,r,v);
            if(r>mid)change_mul(pr,l,r,v);
        }
        inline int ask(Re p,Re w){//单点查询
            Re L=tr[p].l,R=tr[p].r;
            if(L==R)return tr[p].ans;
            pushdown(p);
            if(w<=mid)return ask(pl,w);
            else return ask(pr,w);
        }
    }T1,T2;//T1:x坐标。T2:y坐标。
    inline void sakura(Re T){
    	Re x,y;char op;
    	if(!T)return;
    	scanf(" %c",&op);
        if(op=='m')in(x),in(y);
        sakura(T-1);
        if(op=='x')T1.change_mul(1,1,n,-1);//(x,y) -> (-x,y)
        else if(op=='y')T2.change_mul(1,1,n,-1);//(x,y) ->(x,-y)
        else T1.change_add(1,1,n,x),T2.change_add(1,1,n,y);//(x,y) -> (x+p,y+q)
    }
    int main(){
        // freopen("123.txt","r",stdin);
        in(n),in(T);
        for(Re i=1;i<=n;++i)in(a[i]),in(b[i]);
        T1.build(1,1,n);//第一棵树
    	for(Re i=1;i<=n;++i)a[i]=b[i];
    	T2.build(1,1,n);//第二课树
        sakura(T);
        for(Re i=1;i<=n;++i)printf("%d %d
    ",T1.ask(1,i),T2.ask(1,i));
    }
    
  • 相关阅读:
    bzoj 3040: 最短路(road)
    bzoj 2049: [Sdoi2008]Cave 洞穴勘测
    poj 2505 A multiplication game
    hdu 1729 Stone Game
    经典博弈模型
    hdu 1848 Fibonacci again and again(SG函数)
    hdu 2147 kiki's game(巴什博弈)
    hdu 1847 Good Luck in CET-4 Everybody!(巴什博弈)
    hdu 4388 Stone Game II
    poj 2234 Matches Game
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/11571500.html
Copyright © 2020-2023  润新知