zoukankan      html  css  js  c++  java
  • 【洛谷4739】[CERC2017] Donut Drone(线段树+倍增)

    点此看题面

    • 一个(n imes m)的循环矩阵,每个位置上有一个互不相同的权值。
    • 每次会走到右、右上、右下中权值最大的格子。
    • 初始在((1,1))(q)次操作,分为两种:从当前位置出发走(k)步,并输出到达的位置;修改某个格子上的权值。
    • (n,mle2000,qle5000,kle10^9)

    倍增

    (k)这么大一看就是倍增。

    但我们显然不可能对每个位置都倍增预处理一遍,因为一次修改影响范围可能非常广。

    考虑到(n,m,q)都非常小,实际上我们可以先暴力走到第一列,记(f_{i,j})表示从((i,1))出发走(2^j)轮后会走到((f_{i,j},1)),倍增后再暴力走完余数部分即可。

    这样一来要倍增的位置只有(n)个,即便一次修改使得它们全部发生变化都没关系。

    线段树

    对于线段树上一个区间([l,r])开一个数组(v[rt][i]),表示从((i,l))出发会走到((v_i,r))

    合并的时候先求出((v[lc][i],mid))下一步会走到的位置((w,mid+1)),那么(v[rt][i]=v[rc][w])

    那么((v[1][i],m))下一步会走到的位置就是((f[i][0],1))了。

    代码:(O(nqlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 2000
    #define pre(x) (x^1?x-1:n)
    #define nxt(x) (x^n?x+1:1)
    using namespace std;
    int n,m,a[N+5][N+5],f[N+5][31];
    I int Q(CI x,CI y)//询问(x,y)下一个位置的行号
    {
    	RI tx=x,ty=y^m?y+1:1;return a[pre(x)][ty]>a[tx][ty]&&(tx=pre(x)),a[nxt(x)][ty]>a[tx][ty]&&(tx=nxt(x)),tx;
    }
    class SegmentTree
    {
    	private:
    		#define PT CI l=1,CI r=m,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1
    		int V[N<<2][N+5];I void PU(CI rt,CI mid) {for(RI i=1;i<=n;++i) V[rt][i]=V[rt<<1|1][Q(V[rt<<1][i],mid)];}//合并
    	public:
    		I void Bd(PT)//建树
    		{
    			if(l==r) {for(RI i=1;i<=n;++i) V[rt][i]=i;return;}RI mid=l+r>>1;Bd(LT),Bd(RT),PU(rt,mid);
    		}
    		I void U(CI y,PT)//更新
    		{
    			if(l==r) return;RI mid=l+r>>1;y<=mid?U(y,LT):U(y,RT),PU(rt,mid); 
    		}
    		I void Get()//倍增预处理
    		{
    			RI i,j;for(i=1;i<=n;++i) f[i][0]=Q(V[1][i],m);for(j=1;j<=30;++j) for(i=1;i<=n;++i) f[i][j]=f[f[i][j-1]][j-1];
    		}
    }S;
    int main()
    {
    	RI i,j;for(scanf("%d%d",&n,&m),i=1;i<=n;++i) for(j=1;j<=m;++j) scanf("%d",&a[i][j]);S.Bd(),S.Get();
    	RI Qt,px=1,py=1,x,y,k,t;char s[10];scanf("%d",&Qt);W(Qt--)
    	{
    		if(scanf("%s",s),s[0]=='c') {scanf("%d%d%d",&x,&y,&k),a[x][y]=k,S.U(y^1?y-1:m),S.Get();continue;}//直接修改,然后更新
    		scanf("%d",&k);W(k&&py^1) px=Q(px,py),++py>m&&(py=1),--k;t=k/m,k%=m;//暴力走到第一列
    		for(i=0;i<=30;++i) t>>i&1&&(px=f[px][i]);W(k) px=Q(px,py),++py>m&&(py=1),--k;printf("%d %d
    ",px,py);//倍增后暴力走余数
    	}return 0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Using System Partitioning
    startup命令
    [转]Oracle 10g/11g 密码策略 用户口令 大小写敏感
    [转]Oracle DB 加强的数据安全管理
    Scheduling Jobs with Oracle Scheduler
    [转]Oracle DB SQL 计划管理
    Performing Time-Based or Change-Based Incomplete Recovery
    闪回数据归档
    Managing Optimizer Statistics
    性能测试--十个命令迅速发现性能问题
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4739.html
Copyright © 2011-2022 走看看