题目大意:
给你n个初始化为0的数,m次操作,
每次操作将 l r 区间内的所有小于val的更新为val。
最后查询所有数的异或和。
解题思路:
刚上来队友给我讲了题意后第一反应,这不是个线段树区间更新裸题嘛。但后来一想如果是这样不可能过的人这么少。就强行自己干掉了线段树写法,yy了另一种mlogm的写法,真的智障,T了两发以后发现线段树的复杂度貌似是mlogn的就滚去写线段树了结果1A。中间还尝试过只取最大的10000个val值的写法hhhh ,不过对拍出了一组错误数据就没敢交。。。
最后发现题解的解法真的巧妙,运用了ST表的知识,不过我等凡人就只能搞一搞线段树的暴力写法。
Ac代码:
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int MAX=1e5+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
ll ans;
struct node
{
int l,r,mid; //维护区间最小值
ll val;
}t[MAX<<2];
unsigned X,Y,Z,W;
unsigned f()
{
X=X^(X<<11);
X=X^(X>>4);
X=X^(X<<5);
X=X^(X>>14);
W=X^(Y^Z);
X=Y;
Y=Z;
Z=W;
return Z;
}
void pushup(int rt)
{
t[rt].val=min(t[lson].val,t[rson].val);
}
void pushdown(int rt)
{
if(t[rt].val)
{
t[lson].val=max(t[lson].val,t[rt].val); //pushdown要取较大值
t[rson].val=max(t[rson].val,t[rt].val);
t[rt].val=0;
}
}
void build(int l,int r,int rt)
{
int mid=(l+r)>>1;
t[rt].l=l,t[rt].r=r,t[rt].mid=mid;
t[rt].val=0;
if(l==r)
return ;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(rt);
}
void update(int l,int r,ll val,int rt)
{
if(t[rt].val>=val) return ; //这一步的剪枝很关键
if(l<=t[rt].l&&t[rt].r<=r)
{
if(t[rt].val<=val) t[rt].val=val; //符合要求就更新
return ;
}
pushdown(rt);
if(l<=t[rt].mid) update(l,r,val,lson);
if(r>t[rt].mid) update(l,r,val,rson);
pushup(rt);
}
void query(int l,int r,int rt)
{
if(t[rt].l==t[rt].r)
{
ans=ans^(t[rt].val*t[rt].l); //求答案
return ;
}
pushdown(rt);
query(l,r,lson);
query(l,r,rson);
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
cin>>X>>Y>>Z;
build(1,n,1);
int l,r; ll val;
for(int i=1;i<=m;i++)
{
ll x=f();
ll y=f();
l=min(x%n+1,y%n+1);
r=max(x%n+1,y%n+1);
val=f()%(1<<30);
update(l,r,val,1);
}
ans=0;
query(1,n,1);
printf("%lld\n",ans);
}
return 0;
}