NOIP模拟68
T1 玩水
解题思路
我们称一个点合法当且仅当 \(s_{i-1,j}=s_{i,j-1}\) 。
于是如果一个合法点在它的左上或者右下也可以相邻有一个合法点就是一个合法的图。
树状数组维护即可
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e3+10;
int T,n,m,tre[N][N];
char s[N][N];
int lowbit(int x){return x&(-x);}
void insert(int x,int y,int val)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
tre[i][j]+=val;
}
void clear(int x,int y)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
tre[i][j]=0;
}
int query(int x,int y)
{
int temp=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
temp+=tre[i][j];
return temp;
}
bool judge(int x,int y){return s[x-1][y]==s[x][y-1];}
void solve()
{
n=read(); m=read();
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
for(int i=2;i<=n;i++)
for(int j=2;j<=m;j++)
if(judge(i,j))
{
if(query(i-1,j-1)) return printf("1\n"),void();
if(judge(i-1,j)||judge(i,j-1)) return printf("1\n"),void();
insert(i,j,1);
}
for(int i=2;i<=n;i++)
for(int j=2;j<=m;j++)
if(s[i-1][j]==s[i][j-1])
clear(i,j);
return printf("0\n"),void();
}
signed main()
{
freopen("water.in","r",stdin); freopen("water.out","w",stdout);
T=read(); while(T--) solve();
return 0;
}
T2 假人
优先队列20pts+背包30pts
大坑未补
T3 切题
解题思路
考场上因为数组忘记清空挂了 15pts (45pts code)
虽说是证明看起来高大上,其实就是分别计算每个数对于不同限制的贡献。
线段树维护每一个 \(k\) 的答案,查询最小值。
\(b\) 的值的增减只会影响到 \(c\) 因此对于线段树修改就可以。
\(a\) 的值的修改也只会影响到相邻的值,因此可以树状数组(当然数组也行)查询当前以及更改之后的值按顺序排序的第一个最后一个。
也是线段树上区间修改。
code
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=25e4+10,INF=1e18;
int n,m,lim,q,a[N],b[N],c[N],sa[N],sb[N];
struct BIT
{
int tre[N];
inline int lowbit(int x){return x&(-x);}
inline void insert(int x,int val){if(!x) return;for(int i=x;i;i-=lowbit(i))tre[i]+=val;}
inline int query(int x){x=max(1ll,x);int temp=0;for(int i=x;i<=lim;i+=lowbit(i))temp+=tre[i];return temp;}
}B;
struct Segment_Tree
{
struct Node{int dat,laz;}tre[N<<2];
void push_up(int x){tre[x].dat=min(tre[ls].dat,tre[rs].dat);}
void push_down(int x)
{
if(!tre[x].laz) return ;
tre[ls].dat+=tre[x].laz; tre[ls].laz+=tre[x].laz;
tre[rs].dat+=tre[x].laz; tre[rs].laz+=tre[x].laz;
tre[x].laz=0;
}
void insert(int x,int l,int r,int L,int R,int val)
{
if(L>R) return ;
if(L<=l&&r<=R) return tre[x].dat+=val,tre[x].laz+=val,void();
int mid=(l+r)>>1; push_down(x);
if(L<=mid) insert(ls,l,mid,L,R,val);
if(R>mid) insert(rs,mid+1,r,L,R,val);
push_up(x);
}
}T;
signed main()
{
freopen("problem.in","r",stdin); freopen("problem.out","w",stdout);
n=read(); m=read(); lim=max(n,m);
for(int i=1;i<=n;i++) sa[i]=a[i]=read(),B.insert(a[i],1);
for(int i=1;i<=m;i++) sb[i]=b[i]=read(),c[min(n,b[i])]++;
for(int i=n;i>=1;i--) c[i]+=c[i+1];
sort(sa+1,sa+n+1,greater<int>());
for(int i=1;i<=n;i++) T.insert(1,1,n,i,n,c[i]-sa[i]);
q=read();
while(q--)
{
int opt,pos; opt=read(); pos=read();
if(opt==3){b[pos]++;T.insert(1,1,n,b[pos],n,1);}
if(opt==4){b[pos]--;T.insert(1,1,n,b[pos]+1,n,-1);}
if(opt==1){a[pos]++; B.insert(a[pos]-1,-1); B.insert(a[pos],1);T.insert(1,1,n,B.query(a[pos]),n,-1);}
if(opt==2){a[pos]--; B.insert(a[pos]+1,-1); B.insert(a[pos],1);T.insert(1,1,n,B.query(a[pos]+1)+1,n,1);}
printf("%lld\n",(int)(T.tre[1].dat>=0));
}
return 0;
}
T4 天下第一
需要用到 LCT 。。。