【BZOJ 4524】[CQOI2016] 伪光滑数

相关链接

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4524
正常题面及题解:http://blog.csdn.net/huanghongxun/article/details/51181809

解题报告

考虑按最大的质因子分类
那么每一次就是用次大的质因子去替换最大的质因子
再用堆来维护一下就好了

Code

#include<bits/stdc++.h>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

LL n; int k;
int pri[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127},tot=31;
struct Data{
	LL w; int k,MX,nxt;
	inline Data() {}
	inline Data(LL a, int b, int c, int d):w(a),k(b),MX(c),nxt(d) {}
	inline bool operator < (const Data &B) const {return w < B.w;}
};
priority_queue<Data> que; 

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

int main(){
	cin>>n>>k;
	for (int i=1;i<=tot;i++) {
		LL w = pri[i]; int t = 1;
		while (w <= n) {
			que.push(Data(w,t,i,i-1)),
			w *= pri[i]; t++;
		}
	}
	for (int j=1;j<k;j++) {
		Data t = que.top(); que.pop();
		if (t.k > 1) for (int i=1;i<=t.nxt;i++) {
			LL tmp = t.w / pri[t.MX] * pri[i];
			que.push(Data(tmp,t.k-1,t.MX,i));
		}
	}
	cout<<que.top().w;
	return 0;
}

【BZOJ 4520】[Cqoi2016] K远点对

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4520

这货我最开始写的是二分距离,查询用KD_Tree来查
然而这样的复杂度是没有保障的,于是光荣TLE
其实这货↑是写挂了,连30%的数据都没有拿到分 ←_←

然而这货的正解仍然是KD_Tree
最然感觉时间复杂度比较迷……
就是进入块中时,判断这个块是否能更新答案

#include<bits/stdc++.h>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int N = 100000+9;

struct Point{int x,y;}p[N];
int n,k;
struct CMP{inline bool operator () (const LL A, const LL B){return A>B;}};
priority_queue<LL,vector<LL>,CMP> que; 

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

namespace KD_Tree{
	#define KDT KD_Tree
	int MXx[N],MXy[N],MNx[N],MNy[N],ch[N][2],sz[N];
	int root,ans_tmp,P; LL LEN; 
	
	inline bool cmpx(const Point &A, const Point &B) {return A.x < B.x;}
	inline bool cmpy(const Point &A, const Point &B) {return A.y < B.y;}
	
	inline void update(int w){
		for (int i=0;i<=1;i++) if (ch[w][i]) {
			MXx[w] = max(MXx[w], MXx[ch[w][i]]);
			MXy[w] = max(MXy[w], MXy[ch[w][i]]);
			MNx[w] = min(MNx[w], MNx[ch[w][i]]);
			MNy[w] = min(MNy[w], MNy[ch[w][i]]);
			sz[w] += sz[ch[w][i]];
		}
	}
	
	int build(int l, int r, int ty) {
		int mid = l + r >> 1; sz[mid] = 1;
		if (ty) nth_element(p+l,p+mid,p+r+1,cmpx);
		else nth_element(p+l,p+mid,p+r+1,cmpy);
		MXx[mid] = MNx[mid] = p[mid].x;
		MXy[mid] = MNy[mid] = p[mid].y;
		
		if (l < mid) ch[mid][0] = build(l,mid-1,ty^1);
		if (mid < r) ch[mid][1] = build(mid+1,r,ty^1);
		update(mid); return mid; 
	}inline void build_Tree(){root = build(1,n,1);}
	
	#define Pow(x) ((LL)(x)*(x))
	#define DIS(p1,p2) (Pow(p[p1].x-p[p2].x)+Pow(p[p1].y-p[p2].y))
	
	inline LL judge(int w) {
		LL ret = 0;
		ret += max(Pow(MXx[w]-p[P].x), Pow(MNx[w]-p[P].x));
		ret += max(Pow(MXy[w]-p[P].y), Pow(MNy[w]-p[P].y));
		return ret;
	}
	
	void query(int w) {
		LL dw = DIS(w,P), dl = 0, dr = 0; 
		if (dw > que.top()) que.pop(), que.push(dw);
		if (ch[w][0]) dl = judge(ch[w][0]);
		if (ch[w][1]) dr = judge(ch[w][1]);
		
		if (dl > dr) {
			if (dl > que.top()) query(ch[w][0]);
			if (dr > que.top()) query(ch[w][1]);
		} else {
			if (dr > que.top()) query(ch[w][1]);
			if (dl > que.top()) query(ch[w][0]);
		} 
	} inline void Query(const int po){P = po;query(root);}	
};

int main(){
	n = read(); k = read();
	for (int i=1;i<=n;i++) p[i].x = read(), p[i].y = read();
	for (int i=1;i<=k*2;i++) que.push(0); KDT::build_Tree();
	for (int i=1;i<=n;i++) KDT::Query(i);
	printf("%lld\n",que.top());
	return 0;
}

貌似O(nk)的旋转卡壳也可以过?
貌似网上有一位很激动的同学说一条直线的时候没凸包?
感觉板子如果鲁棒一点的话,没有问题吧?

【Codeforces 703D】Mishka and Interesting sum

题目传送门:http://codeforces.com/contest/703/problem/D
中文题面:http://www.cnblogs.com/zqy123/p/5746481.html

这题,第一眼看到就感觉是莫队
然后算一算复杂度感觉能卡过,于是死坑莫队,遂卒
然后看题解,突然想起来以前做过这么一道题,还有分块的解法
不过最简单的做法,可以记录pre[],然后维护区间的unique之后的值
离线的话,一维BIT即可,不离线的话,可以上函数式线段树

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int N = 1000000+9;

int arr[N],n,m,sum[N],vout[N];
struct Query{
	int l,r,num;
	inline bool operator < (const Query &B) const {
		return r < B.r;
	}
}q[N];
map<int,int> pre;

namespace Fenwick_Tree{
	#define BIT Fenwick_Tree
	#define lowbit(x) ((x)&-(x))
	int v[N];
	
	inline void modify(int i) {
		int tmp = pre[arr[i]]; pre[arr[i]] = i;
		if (tmp) for (int j=tmp;j<=n;j+=lowbit(j)) v[j] ^= arr[i]; 
		for (int j=i;j<=n;j+=lowbit(j)) v[j] ^= arr[i];
	}
	
	inline int query(int l, int r) {
		int ret = 0; l--;
		for (;r;r-=lowbit(r)) ret ^= v[r];
		for (;l;l-=lowbit(l)) ret ^= v[l];
		return ret;
	}
};

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

int main(){
	n = read(); for (int i=1;i<=n;i++) arr[i] = read(); 
	m = read(); for (int i=1;i<=m;i++) q[i].l=read(), q[i].r=read(), q[i].num = i;
	sort(q+1,q+1+m); 
	for (int i=1,cur=1;i<=n;i++) {
		sum[i] = sum[i-1] ^ arr[i]; BIT::modify(i);
		for (;cur <= m && q[cur].r == i;cur++) 
			vout[q[cur].num] = sum[i]^sum[q[cur].l-1]^BIT::query(q[cur].l,q[cur].r);
	}
	for (int i=1;i<=m;i++) printf("%d\n",vout[i]);
	return 0;
}

把BZOJ上那题翻出来了,分块的做法让我们召唤黄学长:http://hzwer.com/3663.html

【BZOJ 2809】[Apio2012] dispatching

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2809

我是来练习斜堆的 = ̄ω ̄=

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<vector>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int N = 100000+9;

LL vout;
int led[N],n,m,arr[N],rt;
vector<int> G[N];

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

namespace Skew_Heap{
	#define SHP Skew_Heap
	int ch[N][2],sz[N],val[N],root[N],cnt;
	LL sum[N];
	
	inline void maintain(int w) {
		sz[w] = sz[ch[w][0]] + sz[ch[w][1]] + 1;
		sum[w] = sum[ch[w][0]] + sum[ch[w][1]] + val[w];
	}
	
	int Merge(int a, int b){
		if (!a || !b) return a+b;
		else {
			if (val[b] > val[a]) swap(a,b);
			ch[a][1] = Merge(ch[a][1],b);
			swap(ch[a][0],ch[a][1]); maintain(a); 
			return a;
		}
	}
	
	inline void pop(int w){
		root[w] = Merge(ch[root[w]][0],ch[root[w]][1]);
	}
	
	inline void insert(int w, int v){
		val[++cnt] = sum[cnt] = v; sz[cnt] = 1;
		root[w] = Merge(root[w],cnt);
	}
};

int main(){
	using namespace Skew_Heap;
	n = read(); m = read();
	for (int i=1,tmp;i<=n;i++) {
		G[read()].push_back(i);
		arr[i] = read(); led[i] = read();
	}
	for (int i=n;i;i--) {
		for (int j=0,lim=G[i].size();j<lim;j++) root[i] = Merge(root[i],root[G[i][j]]);
		insert(i,arr[i]); while (root[i] && sum[root[i]] > m) pop(i);
		vout = max(vout,(LL)sz[root[i]]*led[i]);
	} 
	printf("%lld\n",vout);
	return 0;
}

【HDU 1754】I Hate It

题目传送门:http://acm.split.hdu.edu.cn/showproblem.php?pid=1754
中文题面:http://blog.csdn.net/scnu_jiechao/article/details/8574166

其实我是来水BIT的

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int N = 200000+9;
const int INF = 1000000000;

int n,m;
char pat[10];

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

namespace Fenwick_Tree{
	#define BIT Fenwick_Tree
	#define lowbit(x) ((x)&(-(x)))
	int MX[N],arr[N];
	
	inline void init(){
		for (int i=1;i<=n;i++)
			MX[i] = -INF;
	}
	
	inline void modify(int pos, int val){
		int pre = arr[pos]; arr[pos] = val;
		if (val >= pre) {
			for (int i=pos;i<=n;i+=lowbit(i)) 
				MX[i] = max(MX[i],val);
		} else {
			for (int i=pos;i<=n;i+=lowbit(i)) {
				MX[i] = arr[i];
				for (int j=lowbit(i)/2;j;j>>=1) 
					MX[i] = max(MX[i],MX[i-j]);
			}
		}
	}
	
	inline int query(int l, int r) {
		int ret = -INF;
		while (r >= l) {
			if (r-lowbit(r)+1 >= l) ret = max(ret, MX[r]), r -= lowbit(r);
			else ret = max(ret, arr[r]), r--;
		}
		return ret;
	}
};

int main(){
	while (~scanf("%d%d",&n,&m)) {
		BIT::init();
		for (int i=1;i<=n;i++) BIT::modify(i,read());	
		for (int i=1,l,r;i<=m;i++) {
			scanf("%s",pat+1);
			if (pat[1] == 'Q') l = read(), r = read(), printf("%d\n",BIT::query(l,r));
			else l = read(), r = read(), BIT::modify(l, r); 
		}
	}
	return 0;
}

【Codeforces 708C】Centroids

题目传送门:http://codeforces.com/problemset/problem/708/C

我是函数式线段树+出栈入栈序的做法(其实一个RMQ即可)
但这题可以O(n)DP!记录子树中,最大的,不超过n/2的值是多少

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int N = 800000+9;
const int M = 20000000;
const int INF = 1000000000;

int n,tot[N],ls[N],sig,rs[N],head[N],to[N],nxt[N],vex[N*2];

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

namespace Chair_Tree{
	#define CT Chair_Tree
	int sum[M][2],ch[M][2],cnt,root[N],ans_tmp;
	
	void Add(int p, int &w, int l, int r, int pos, int ty) {
		w = ++cnt; ch[w][0] = ch[p][0]; ch[w][1] = ch[p][1]; 
		sum[w][0] = sum[p][0]; sum[w][1] = sum[p][1]; sum[w][ty]++;
		if (l < r) {
			int mid = l + r + 1 >> 1;
			if (pos < mid) Add(ch[p][0],ch[w][0],l,mid-1,pos,ty);
			else Add(ch[p][1],ch[w][1],mid,r,pos,ty);
		}
	} 
	
	inline void modify(int i, int val) {
		if (val > 0) Add(root[i-1],root[i],1,n,val,1);
		else Add(root[i-1],root[i],1,n,-val,0);
	}
	
	void query(int w, int l, int r, int L, int R, int f, int ty){
		if (L <= l && r <= R) ans_tmp += sum[w][ty]*f;
		else {
			int mid = l + r + 1 >> 1;
			if (L < mid) query(ch[w][0],l,mid-1,L,R,f,ty);
			if (R >= mid) query(ch[w][1],mid,r,L,R,f,ty);
		}
	}
	
	inline int query(int l, int r, int L, int R,int ty) {
		if (l > r) return false;
		ans_tmp = 0;
		query(root[l-1],1,n,L,R,-1,ty);
		query(root[r],1,n,L,R,1,ty);
		return ans_tmp;
	}
	
	inline void Merge(){
		for (int i=1;i<=cnt;i++) 
			sum[i][0] = sum[i][1] - sum[i][0];
	}
};

void DFS(int w, int f) {
	tot[w] = 1; ls[w] = ++sig; 
	for (int i=head[w];i;i=nxt[i]) if (to[i] != f)
		DFS(to[i],w), tot[w] += tot[to[i]];
	rs[w] = ++sig; 
	vex[ls[w]] = tot[w];
	vex[rs[w]] = -tot[w];
}

inline void AddEdge(int a, int b) {
	static int T = 0;
	to[++T] = b; nxt[T] = head[a]; head[a] = T;
	to[++T] = a; nxt[T] = head[b]; head[b] = T;
}

inline bool judge(int w) {
	int MX = 0, vx = 0, MN, ty, sta;
	for (int i=head[w];i;i=nxt[i]) 
		if (ls[w] < ls[to[i]] && ls[to[i]] <= rs[w]) {if (MX < tot[to[i]]) MX = tot[to[i]], vx = to[i], ty = 0;} 
		else {int tmp = n - tot[w]; if (MX < tmp) MX = tmp, vx = to[i], ty = 1;}
	if (MX <= n/2) return 1;
	else {
		sta = n/2;
		MN = MX-n/2;
		if (!ty) return CT::query(ls[vx],rs[vx],MN,sta,1);
		else {
			int tmp = CT::query(1,ls[w]-1,MN,sta,1) + CT::query(rs[w]+1,n*2,MN,sta,1);
			tmp -= CT::query(1,ls[w]-1,MN,sta,0); MN = n - MN; sta = n - sta; swap(MN,sta);
			tmp += CT::query(2,ls[w],MN,sta,0);
			return tmp;
		}
	}
}

int main(){
	n = read(); 
	for (int i=1;i<n;i++) AddEdge(read(),read()); DFS(1,1);
	for (int i=1;i<=n*2;i++) CT::modify(i,vex[i]); CT::Merge();
	for (int i=1;i<=n;i++) printf("%d ",judge(i));
	return 0;
}

【Codeforces 707E】Garlands

题目传送门:http://codeforces.com/contest/707/problem/E
中文题面:http://blog.csdn.net/kg20006/article/details/52275809

对于每一个链单独考虑,算对于答案的贡献
时间复杂度:\(O(k \cdot {\log _2}{(n)^2} \cdot (len + q))\)

然后在算贡献那里,可以用二维树状数组
但我的代码跑了1100ms,有一份代码只跑了700ms
于是去看了看,突然想起来,这种不带修改的二维树状数组
可以把询问记下来,按照横坐标排序,然后转化为一维树状数组
好像要稍微快一点,不过我还是写的二维的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define LL long long
#define lowbit(x) ((x)&(-(x)))
using namespace std;

const int N = 2000+9;
const int M = 4000000+9;
const int INF = 1000000000;

int q,head[N],Y[M],n,m,k,X[M],W[M],nxt[M],tot,x1[N],x2[N],y1[N],y2[N],tme[N];
LL mat[N][N],vout[N];
queue<int> que[N]; 
char pat[N];

inline int read(){
	char c=getchar(); int ret=0;
	while (c<'0'||c>'9') c=getchar();
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret;
}

inline void Add(int len, int num){
	static int T = 0;
	for (int i=1;i<=len;i++) {
		nxt[++T] = head[num]; X[T] = read(); 
		Y[T] = read(); W[T] = read(); head[num] = T;
	}
}

inline void modify(int x, int y, int w){
	for (int j=y;j<=m;j+=lowbit(j))
		for (int i=x;i<=n;i+=lowbit(i))
			mat[i][j] += w; 
}

inline LL query(int x, int y){
	LL ret = 0;
	for (int j=y;j;j-=lowbit(j)) 
		for (int i=x;i;i-=lowbit(i))
			ret += mat[i][j];
	return ret;
}

int main(){
	n = read(); m = read(); k = read();
	for (int i=1;i<=k;i++) Add(read(),i);
	q = read(); for (int i=1;i<=q;i++) {
		scanf("%s",pat+1);
		if (pat[1] == 'S') que[read()].push(i);	
		else {
			tme[++tot] = i;
			x1[tot] = read(); y1[tot] = read();
			x2[tot] = read(); y2[tot] = read();
		}
	} 
	for (int i=1;i<=k;i++) que[i].push(INF);
	for (int i=1;i<=k;i++) {
		for (int j=head[i];j;j=nxt[j]) modify(X[j],Y[j],W[j]);
		int sta = 1,T=1; while (!que[i].empty()) {
			int w = que[i].front(); que[i].pop(); sta ^= 1;
			while (T <= tot && tme[T] < w) {
				int p = T++; if (sta^1) 		
				vout[p] += query(x1[p]-1,y1[p]-1) + query(x2[p],y2[p]) - query(x1[p]-1,y2[p]) - query(x2[p],y1[p]-1);
			}
		}
		for (int j=head[i];j;j=nxt[j]) modify(X[j],Y[j],-W[j]);
	} 
	for (int i=1;i<=tot;i++) printf("%I64d\n",vout[i]);
	return 0;
}

【POJ 3522】Slim Span

题目传送门:http://poj.org/problem?id=3522

今天在水位运算生成树,无聊来水一水
很暴力,枚举最大边,然后搞一搞,并查集判树

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N = 100+9;
const int M = 10000+9;
const int INF = 1000000000;

struct Edge{int u,v,w;}e[M];
int n,m,vout,fa[N];

inline bool operator < (const Edge &A, const Edge &B) {return A.w < B.w;}

inline int read(){
	char c=getchar(); int ret=0;
	while (c<'0'||c>'9') c=getchar();
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret;
}

inline int find(int w){
	int f=fa[w],tmp;
	while (fa[f] != f) f = fa[f];
	while (w != f) tmp=fa[w], fa[w]=f, w=tmp;
	return f;
}

inline int Get_Ans(int lim){
	for (int i=1;i<=n;i++) fa[i] = i;
	fa[e[lim].u] = fa[e[lim].v];
	for (int i=lim-1,t=n-2,f1,f2;i;i--) {
		f1 = find(e[i].u); f2 = find(e[i].v);
		if (f1 != f2) fa[f2] = f1, t--;
		if (!t) return e[i].w;
	}
	return -INF;
}

int main(){
	while (scanf("%d%d",&n,&m) && (n||m)) {
		for (int i=1;i<=m;i++) e[i].u = read(), e[i].v = read(), e[i].w = read();
		sort(e+1,e+1+m); vout = INF;
		for (int lim=m;lim>=n-1;lim--) 
			vout = min(vout, e[lim].w - Get_Ans(lim));
		if (n <= 2) printf("0\n");
		else printf("%d\n",vout>=INF?-1:vout);	
	}
	return 0;
}

【Codeforces 707D】Persistent Bookcase

题目链接:http://codeforces.com/problemset/problem/707/D

这个东西,一开始写了一个严格小于O(n*q*log(q))的算法,结果T到死QAQ
然后看到了这一篇blog:http://h0rnet.hatenablog.com
发现严格O(n*q)的暴力都可过QAQ
然而感觉这样暴力一点都不清真啊!虽然只跑了200ms多一点

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int n,m,q;

namespace Chair_Tree{
	#define CT Chair_Tree
	const int MAXN = 2000000;
	const int N = 1000+9;
	const int Q = 100000+9;
	
	int ls[MAXN],rs[MAXN],sum[MAXN],TY,ans_tmp,cnt,tmp_root,pr[N],pv[N],vout[Q];
	int root[Q][N]; bool rev[Q][N];
	
	inline void Clone(int p, int w) {
		memcpy(root[w],root[p],sizeof(root[w]));
		memcpy(rev[w],rev[p],sizeof(rev[w]));
		vout[w] = vout[p];
	}
	
	void modify(int p, int &w, int l, int r, int pos){
		w = ++cnt; ls[w] = ls[p]; rs[w] = rs[p]; sum[w] = sum[p];
		if (l < r) {
			int mid = l + r + 1 >> 1;
			if (pos < mid) modify(ls[p],ls[w],l,mid-1,pos);
			else modify(rs[p],rs[w],mid,r,pos);
			sum[w] = sum[ls[w]] + sum[rs[w]];
		} else if (sum[w] + TY == 1) sum[w] ^= 1, ans_tmp = 1;
	}
	
	inline int modify(int i, int j, int ty, int k){
		Clone(k-1,k); ans_tmp = 0; TY = ty^rev[k][i]; 
		modify(root[k][i],tmp_root,1,m,j); root[k][i] = tmp_root;
		if (ty == 1) vout[k] += ans_tmp;
		else vout[k] -= ans_tmp;
		return vout[k];
	}
	
	inline int REV(int i,int k){
		Clone(k-1,k); rev[k][i] ^= 1;
		int tmp = sum[root[k-1][i]], w=tmp;
		if (rev[k-1][i]) tmp = m - tmp;
		else w = m - w; vout[k] += w - tmp;
		return vout[k];
	}	
};

inline int read(){
	char c=getchar(); int ret=0;
	while (c<'0'||c>'9') c=getchar();
	while (c<='9'&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret;
}

int main(){
	cin>>n>>m>>q; 
	for (int i=1,ty,x,y;i<=q;i++) {
		ty = read();
		if (ty == 1) {
			x = read(); y = read();
			printf("%d\n",CT::modify(x,y,1,i));
		} else if (ty == 2) {
			x = read(); y = read();
			printf("%d\n",CT::modify(x,y,0,i));
		} else if (ty == 3) printf("%d\n",CT::REV(read(),i));
		else CT::Clone(read(),i), printf("%d\n",CT::vout[i]);
	} 
	return 0;
}

还有那个离线的版本,真的是一点都不清真啊!

【Codeforces 706E】Working routine

题目传送门:http://codeforces.com/problemset/problem/706/E
官方题解:http://codeforces.com/blog/entry/46510

这个题感觉出得很好啊!
没想到链表还能这么考!秒啊!
23781763871263

#include<iostream>
#include<cstdio>
using namespace std;

const int MAXN = 1000+9;

int d[MAXN*MAXN],r[MAXN*MAXN],mat[MAXN*MAXN],m,n,q,vout[MAXN][MAXN];

inline int read(){
	char c=getchar(); int ret = 0;
	while (c<'0'||c>'9') c=getchar();
	while (c<='9'&&c>='0') ret = ret*10+c-'0', c=getchar();
	return ret;
}

#define id(x, y) ((x)+1 + (y)*(n+2))

inline void change(int x1, int y1, int x2, int y2, int x, int y){
	int p1 = id(0,0), p2 = id(0,0); 
	for (int j=1;j<y1;j++) p1 = d[p1]; for (int i=1;i<=x1;i++) p1 = r[p1];
	for (int j=1;j<y2;j++) p2 = d[p2]; for (int i=1;i<=x2;i++) p2 = r[p2];
	for (int i=1;i<=x;i++) swap(d[p1], d[p2]), p1 = r[p1], p2 = r[p2];
	p1 = id(0,0), p2 = id(0,0); 
	for (int j=1;j<y1+y;j++) p1 = d[p1]; for (int i=1;i<=x1;i++) p1 = r[p1];
	for (int j=1;j<y2+y;j++) p2 = d[p2]; for (int i=1;i<=x2;i++) p2 = r[p2];
	for (int i=1;i<=x;i++) swap(d[p1], d[p2]), p1 = r[p1], p2 = r[p2];
	
	
	p1 = id(0,0), p2 = id(0,0); 
	for (int i=1;i<x1;i++) p1 = r[p1]; for (int j=1;j<=y1;j++) p1 = d[p1]; 
	for (int i=1;i<x2;i++) p2 = r[p2]; for (int j=1;j<=y2;j++) p2 = d[p2];
	for (int j=1;j<=y;j++) swap(r[p1], r[p2]), p1 = d[p1], p2 = d[p2];
	p1 = id(0,0), p2 = id(0,0); 
	for (int i=1;i<x1+x;i++) p1 = r[p1]; for (int j=1;j<=y1;j++) p1 = d[p1]; 
	for (int i=1;i<x2+x;i++) p2 = r[p2]; for (int j=1;j<=y2;j++) p2 = d[p2];
	for (int j=1;j<=y;j++) swap(r[p1], r[p2]), p1 = d[p1], p2 = d[p2];
}

inline void trans(){
	int head = id(0,0); 
	for (int j=1;j<=m;j++) {
		head = d[head];
		for (int i=1,w=r[head];i<=n;i++,w=r[w])
			vout[i][j] = mat[w];
	}
	for (int j=1;j<=m;j++) {for (int i=1;i<=n;i++) printf("%d ",vout[i][j]); printf("\n");}
}

int main(){
	m = read(); n = read(); q = read();
	for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) mat[id(i,j)] = read();
	for (int j=0;j<=m+1;j++) for (int i=0;i<=n+1;i++) d[id(i,j)] = id(i,j+1), r[id(i,j)] = id(i+1,j);
	
	for (int k=1,x1,x2,y1,y2,lh,lw;k<=q;k++) {
		y1 = read(), x1 = read();
		y2 = read(), x2 = read();
		lh = read(), lw = read();
		change(x1,y1,x2,y2,lw,lh);
	} trans();
	return 0;
}

【Codeforces 706D】Vasiliy’s Multiset

题目传送门:http://codeforces.com/contest/706/problem/D

可持久化字典树,解决xor

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
using namespace std;

const int MAXN = 7000000;
const int SGZ = 40;

int n;

map<int,int> M;

inline int read(){
	char c=getchar(); int ret = 0;
	while (c<'0'||c>'9'){c=getchar();}
	while (c<='9'&&c>='0'){ret=ret*10+c-'0';c=getchar();}
	return ret;
}

inline int Get(){
	char c=getchar(); 
	while (c != '+' && c != '-' && c != '?') c=getchar();
	if (c == '+') return 1;
	else if (c == '-') return -1;
	else return 0;
}

namespace Chair_Tree{
	#define CT Chair_Tree
	int ans_tmp,cnt,ch[MAXN][2],buf[SGZ],root,sum[MAXN];
	
	void modify(int pre, int &w, int step, int delta){
		w = ++cnt; sum[w] = sum[pre] + delta; ch[w][0] = ch[pre][0]; ch[w][1] = ch[pre][1];
		if (step <= 31) modify(ch[pre][buf[step]],ch[w][buf[step]],step+1,delta);
	}
	
	inline void modify(int val, int delta){
		for (int i=1;i<=31;i++) buf[31-i+1] = val & 1, val >>= 1;
		modify(root, root, 1, delta); 	
	}
	
	void query(int w, int step){
		if (step <= 31) {
			if (sum[ch[w][buf[step]]]) ans_tmp += 1<<(31-step), query(ch[w][buf[step]],step+1);
			else query(ch[w][buf[step]^1],step+1);
		}
	}
	
	inline int query(int val){
		ans_tmp = 0;
		for (int i=1;i<=31;i++) buf[31-i+1] = (val & 1) ^ 1, val >>= 1;
		query(root, 1); 
		return ans_tmp;
	}
};

int main(){
	n = read(); CT::modify(0,1);
	for (int i=1,tp,val;i<=n;i++) {
		tp = Get(); val = read();
		if (tp == 1) {
			M[val] = M[val] + 1;
			if (M[val] == 1) CT::modify(val,1);
		} else if (tp == -1) {
			M[val] = M[val] - 1;
			if (M[val] == 0) CT::modify(val,-1);
		} else printf("%d\n",CT::query(val));
	}
	return 0;
} 

【POJ 3074】Sudoku

题目传送门:http://poj.org/problem?id=3074

Dancing_links

#include<iostream>
#include<cstdio>
using namespace std;

char pat[90];
int grid[10][10]={
	{0,0,0,0,0,0,0,0,0,0},
	{0,1,1,1,4,4,4,7,7,7},
	{0,1,1,1,4,4,4,7,7,7},
	{0,1,1,1,4,4,4,7,7,7},
	{0,2,2,2,5,5,5,8,8,8},
	{0,2,2,2,5,5,5,8,8,8},
	{0,2,2,2,5,5,5,8,8,8},
	{0,3,3,3,6,6,6,9,9,9},
	{0,3,3,3,6,6,6,9,9,9},
	{0,3,3,3,6,6,6,9,9,9}
};

namespace Dancing_link{
	#define DL Dancing_link
	const int MX = 324;
	const int N = 1000000;
	int rma,cnt,L[N],R[N],U[N],D[N],sz[N],col[N],p[N],v[N];
	
	
	inline void init(){
		rma = 0; cnt = MX;
		for (int i=0;i<=MX;i++) L[i] = i-1, R[i] = i+1, U[i] = i, D[i] = i, sz[i] = 0;
		L[0] = MX; R[MX] = 0;
	}
	
	inline void AddRow(int n, int pos, int val, int *arr){
		for (int i=1,w;i<=n;i++) {
			w = ++cnt; p[w] = pos; v[w] = val;
			col[w] = arr[i]; sz[arr[i]]++;
			L[w+1] = w; R[w] = w+1; 
			D[U[arr[i]]] = w; D[w] = arr[i];
			U[w] = U[arr[i]]; U[arr[i]] = w; 
		}
		L[cnt-n+1] = cnt; R[cnt] = cnt-n+1;
	}
	
	inline void remove(int w){
		L[R[w]] = L[w];
		R[L[w]] = R[w];
		for (int i=D[w];i!=w && i;i=D[i]) for (int j=R[i];j!=i;j=R[j])
			D[U[j]] = D[j], U[D[j]] = U[j], sz[col[j]]--;
	}
	
	inline void restore(int w){
		for (int i=U[w];i!=w && i;i=U[i]) for (int j=L[i];j!=i;j=L[j])
			D[U[j]] = j, U[D[j]] = j, sz[col[j]]++;
		L[R[w]] = w;
		R[L[w]] = w;
	}
	
	bool solve(int d){
		if (d == rma+1) return true;
		
		int w = R[0];
		for (int i=R[w];i;i=R[i]) if (sz[i] < sz[w]) w = i;
		
		remove(w);
		for (int i=D[w];i!=w;i=D[i]) {
			pat[p[i]] = v[i]+'0'; 
			for (int j=R[i];j!=i;j=R[j]) remove(col[j]);
			if (solve(d+1)) return true;
			for (int j=R[i];j!=i;j=R[j]) restore(col[j]); 
		}
		restore(w);
		
		return false;
	}
};

inline int ID(int t, int pos, int val) {
	return 81*(t-1)+9*(pos-1)+val;
}

inline void build_link(){
	static int tmp[10]; DL::init();
	for (int j=1,w=1;j<=9;j++) for (int i=1;i<=9;i++,w++) if (pat[w] == '.') {
		for (int k=1;k<=9;k++) {
			tmp[1] = ID(1,i,k);
			tmp[2] = ID(2,j,k);
			tmp[3] = ID(3,grid[i][j],k);
			tmp[4] = 243+w;
			DL::AddRow(4,w,k,tmp);
		}
		DL::rma++; 
	}
	 for (int j=1,w=1;j<=9;j++) for (int i=1;i<=9;i++,w++) if (pat[w] != '.') { 
		int c = pat[w]-'0';
		DL::remove(ID(1,i,c));
		DL::remove(ID(2,j,c));
		DL::remove(ID(3,grid[i][j],c));
		DL::remove(243+w);
	}
}

int main(){
	while (~scanf("%s",pat+1) && pat[1] != 'e') {
		build_link();
		if (DL::solve(1)) printf("%s\n",pat+1);
		else printf("No solution\n");
	}
	return 0;
}

【UOJ 218】[UNR #1] 火车管理

题目传送门:http://uoj.ac/problem/218
数据生成器:http://paste.ubuntu.com/20456908/

这一道题目,考试的时候,还是想要A掉来着,结果wa得只剩10分QAQ
™我的自定义测试,那么大的数据都没有wa

考试的时候,我的做法是:
单独一棵线段树用来处理询问
然后再用一个二维线段树来维护堆栈
第一维是时间,用来二分最近最近的有效操作
第二维是车站,用来支持二分的查询动作
时间复杂度:O(nlog^2(n))

std的做法是:
任然单独搞一棵线段树来对付询问
对于操作,直接上函数式线段树QAQ
时间复杂度:O(nlogn)

至今都觉得还是我的做法最自然
但他们都说函数式线段树最自然QAQ

#include<iostream>
#include<cstdio>
using namespace std;

const int MAXN = 500000+9;

int n,m,ty,last_ans,arr[MAXN];

inline int read(){
	char c=getchar(); int buf=0,f=1;
	while (c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0'){buf=buf*10+c-'0';c=getchar();}
	return (buf*f+last_ans*ty) % n + 1;
}

namespace Segment_Tree{
	#define SEG Segment_Tree
	const int N = MAXN*4;
	int tag[N],sum[N],tm[N],ans_tmp,L,R,DEL;
	
	inline void push_down(int w, int l, int r, int mid){
		tag[w*2] = tag[w*2+1] = tag[w];
		sum[w*2] = (mid-l)*arr[tag[w]];
		sum[w*2+1] = (r-mid+1)*arr[tag[w]];
		tag[w] = 0;
	}
	
	void query(int w, int l, int r){
		if (L <= l && r <= R) ans_tmp += sum[w];
		else {
			int mid = (l + r + 1) / 2;
			if (tag[w]) push_down(w,l,r,mid);
			if (L < mid) query(w*2,l,mid-1);
			if (R >= mid) query(w*2+1,mid,r);
		}
	}inline int query(int l, int r){ans_tmp=0;L=l,R=r;query(1,1,n);return ans_tmp;}
	
	void Modify(int w, int l, int r){
		if (L <= l && r <= R) tag[w] = DEL, sum[w] = (r-l+1)*arr[DEL];
		else {
			int mid = (l + r + 1) / 2;
			if (tag[w]) push_down(w,l,r,mid);
			if (L < mid) Modify(w*2,l,mid-1);
			if (R >= mid) Modify(w*2+1,mid,r);
			sum[w] = sum[w*2] + sum[w*2+1];
		}
	}inline void modify(int l, int r, int del){L=l,R=r,DEL=del;Modify(1,1,n);}
	
	inline int index(int pos){
		int w = 1, l = 1, r = n, mid;
		while (l < r) {
			if (tag[w]) return tag[w];
			else {
				mid = (l + r + 1) / 2;
				if (pos < mid) w = w*2, r = mid-1;
				else w = w*2+1, l = mid;
			}
		}
		return tag[w];
	}
}; 

namespace Persistent_Segment_Tree{
	#define PST Persistent_Segment_Tree
	const int N = 20000000;
	int tag[N],root[N],ch[N][2],tot,cnt,L,R,DEL;
	
	inline int query(int tm, int pos) {
		if (tm < 1) return 0;
		else {
			int w = root[tm], l=1, r=n, mid;
			while (l < r) {
				if (tag[w]) return tag[w];
				else {
					mid = (l + r + 1) / 2;
					if (pos < mid) w = ch[w][0], r = mid-1;
					else w = ch[w][1], l = mid;
				}
			}
			return tag[w];
		}
	}
	
	inline void push_down(int w){
		for (int i=0;i<=1;i++) if (!ch[w][i]) ch[w][i] = ++cnt;
		for (int i=0;i<=1;i++) tag[ch[w][i]] = tag[w];
		tag[w] = 0;
	}
	
	void Modify(int pre, int &w, int l, int r, int tg){
		w = ++cnt; ch[w][1] = ch[pre][1]; 
		ch[w][0] = ch[pre][0]; tag[w] = tg?tg:tag[pre];
		if (L <= l && r <= R) tag[w] = DEL;
		else {
			int mid = (l + r + 1) / 2; 
			if (L < mid) Modify(ch[pre][0],ch[w][0],l,mid-1,tag[w]);
			else if (tag[w]) ch[w][0] = ++cnt, tag[cnt] = tag[w];
			if (mid <= R) Modify(ch[pre][1],ch[w][1],mid,r,tag[w]);
			else if (tag[w]) ch[w][1] = ++cnt, tag[cnt] = tag[w];
			tag[w] = 0;
		}
	}
	
	inline int modify(int l, int r, int val, bool type){
		L = l, R = r, DEL = val; 
		Modify(root[tot], root[(tot+type)], 1, n, 0);
		tot += type; return tot;
	}
};

int main(){
	scanf("%d%d%d",&n,&m,&ty);
	for (int i=1,type,l,r,del;i<=m;i++){
		scanf("%d",&type);
		if (type == 1) {
			l = read(); r = read();
			if (l > r) swap(l, r);
			printf("%d\n",last_ans=SEG::query(l,r));
		} else if (type == 2) {
			l = read();
			int tmp = SEG::index(l);
			int nv = PST::query(tmp-1,l);
			PST::modify(l,l,nv,0);
			SEG::modify(l,l,nv);
		} else {
			l = read(); r = read(); scanf("%d",&del);
			if (l > r) swap(l, r); 
			int tmp = PST::modify(l,r,PST::tot+1,1);
			arr[tmp] = del;
			SEG::modify(l, r, tmp);
		}
	}
	return 0;
}

【UOJ 213】[UNR #1] 争夺圣杯

题目传送门:http://uoj.ac/problem/213
原厂题解:http://c_sunshine.blog.uoj.ac/blog/1860

我发现这道题目,我写了30分的暴力,60分的乱搞,100分的乱搞QAQ

说一说100分的乱搞O(nlogn):
考虑每一个区间的右端点右移一格,左端点不动
那么区间mx要么变成最右边那个,要么不动
考虑计算最右边那货对于答案的贡献,实际上就是区间加减
于是线段树维护一下

其实搞到这里,O(n)的做法就很明显了
因为线段树那里,只需要区间加减,不需要支持中途询问
于是搞一个差分就可以把线段树给去掉

#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;

const int MAXN = 1000000+9;
const int MOD = 998244353;

int n,arr[MAXN],vout,que[MAXN],lft[MAXN],MX[MAXN],BUF[MAXN]; 

inline int read(){
	char c=getchar(); int buf=0,f=1;
	while (c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0'){buf=buf*10+c-'0';c=getchar();}
	return buf*f;
}

inline void prework(){
	int tot = 0;
	for  (int i=1;i<=n;i++) {
		while (tot && arr[que[tot]] < arr[i]) tot--;
		BUF[1] = (BUF[1]+arr[i])%MOD;
		BUF[i-que[tot]+1] = ((BUF[i-que[tot]+1] - arr[i]) % MOD + MOD ) %MOD;
		lft[i] = i-que[tot]; que[++tot] = i; 
	} tot = 0; que[0] = n+1;
	for (int i=n;i;i--) {
		while (tot && arr[que[tot]] <= arr[i]) tot--;
		if(tot) {
			BUF[que[tot]-i+1] = ((BUF[que[tot]-i+1]-arr[i]) % MOD + MOD) % MOD; 
			BUF[que[tot]-i+lft[i]+1] = (BUF[que[tot]-i+lft[i]+1] + arr[i]) % MOD;
		} que[++tot] = i;
	}
	for (int i=n;i;i--) MX[i] = max(MX[i+1], arr[i]);
}

inline void solve(){
	int tmp = 0, delta = 0;
	for (int i=1;i<=n;i++) {
		delta = ((delta + BUF[i]) % MOD + MOD) % MOD;
		tmp = ((tmp + delta) % MOD + MOD) % MOD;
		vout ^= tmp;
		tmp -= MX[n-i+1];
	}
}

int main(){
	n = read();
	for (int i=1;i<=n;i++) arr[i] = read();
	prework(); solve();
	printf("%d\n",vout);
	return 0;
}

【NOI五连测】[D2T2] 取名字

题目传送门:http://pan.baidu.com/s/1hsLh92W
OJ传送门:http://oi.cdshishi.net:8080/Problem/1713

这一道题目,考试的时候,想了一个小时,完全没有思路,最后搞了30分的暴力QAQ
考试的时候一直在想如何将更改操作应用于硬币上
然而std是用硬币去操作中查询
为什么考试的时候没有想到呢?考试的时候是想到这样反向来搞的,但因为精神不好+懒所以没有深入思考
所以该睡的觉还是要睡的,该开的黑还是要开的

来说一说std的做法:
设一个硬币,比较大的值为mx,较小的值为mn。操作的阈值为v
则操作可以分为3类
1.mn < v
2.mn <= v < mx
3.mx <= v
对于第一类,明显不影响
对于第二类,明显是不管之前状态如何,全部变为mx
对于第三类,就是直接反转
所以我们可以找到最后一个第二类操作,然后查找之后有多少个三类操作即可

至于代码实现方面,我后来写的是BIT+线段树
std是二维线段树
我的要快一点,std空间要少很多,所以还是把std贴出来吧(std建树的时候有一点奇技淫巧)
std:http://paste.ubuntu.com/19496714/
my code:

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#define LL long long
using namespace std;

const int MAXN = 100000+9;

int n,m,arr[MAXN],rev[MAXN],val[MAXN],hash[MAXN*3],tot,MX;
vector<int> G[MAXN]; LL vout;

inline int read(){
	char c=getchar(); int buf=0,f=1;
	while (c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0'){buf=buf*10+c-'0';c=getchar();}
	return buf*f;
} 

namespace Chair_Tree{
	#define CT Chair_Tree
	#define lowbit(x) ((x)&-(x))
	#define N 10000000
	int cnt,ch[N][2],sum[N],ans_tmp;
	int q1[MAXN],q2[MAXN],root[MAXN*3];
	
	void modify(int &w, int l, int r, int val, int del){
		if (!w) w = ++cnt; sum[w] += del; 
		if (l < r) {
			int mid = (l + r + 1) / 2;
			if (val < mid) modify(ch[w][0],l,mid-1,val,del);
			else modify(ch[w][1],mid,r,val,del);
		}
	}
	
	inline void modify(int pos, int val, int del){
		for (int i=val;i<=tot;i+=lowbit(i)) 
			modify(root[i],1,m,pos,del);
	}
	
	void query(int w, int l, int r, int lim, int rim){
		if (lim <= l && r <= rim) ans_tmp += sum[w];
		else {
			int mid = (l + r + 1) / 2;
			if (lim < mid) query(ch[w][0],l,mid-1,lim,rim); if (rim >= mid) query(ch[w][1],mid,r,lim,rim); 
		}
	}
	
	inline int query(int pos, int l, int r){
		ans_tmp = 0; 
		for (int i=pos;i;i-=lowbit(i)) 
			query(root[i],1,m,l,r);
		return ans_tmp;
	}
	
	inline int GetMX(int L, int R) {
		int t1=0,t2=0,l=1,r=m,mid,tmp=0;
		for (int i=R;i;i-=lowbit(i)) q1[++t1] = root[i];
		for (int i=L;i;i-=lowbit(i)) q2[++t2] = root[i];
		for (int i=1;i<=t1;i++) tmp += sum[q1[i]];
		for (int i=1;i<=t2;i++) tmp -= sum[q2[i]];
		if (!tmp) return 0;
		else while (l < r) {
			mid = (l + r + 1) / 2; tmp = 0;
			for (int i=1;i<=t1;i++) tmp += sum[ch[q1[i]][1]];
			for (int i=1;i<=t2;i++) tmp -= sum[ch[q2[i]][1]]; if (tmp > 0) {
				l = mid;
				for (int i=1;i<=t1;i++) q1[i] = ch[q1[i]][1];
				for (int i=1;i<=t2;i++) q2[i] = ch[q2[i]][1];
			} else {
				r = mid - 1;
				for (int i=1;i<=t1;i++) q1[i] = ch[q1[i]][0];
				for (int i=1;i<=t2;i++) q2[i] = ch[q2[i]][0];
			}
		} return l;
	}
};

inline int find(int w){
	int l=1,r=tot,mid;
	while (l <= r) {
		mid = (l + r) / 2;
		if (hash[mid] < w) l = mid+1; else if (hash[mid] > w) r = mid-1;
		else return mid;;
	}
}

int main(){
	freopen("name.in","r",stdin);
	freopen("name.out","w",stdout); 
	n = read();
	for (int i=1;i<=n;i++) arr[i] = hash[++tot] = read();
	for (int i=1;i<=n;i++) rev[i] = hash[++tot] = read();
	m = read();
	for (int i=1,a,b,c;i<=m;i++) 
		a = read(), b = read(), val[i] = hash[++tot] = read(),
		G[a].push_back(i), G[b+1].push_back(-i);
	sort(hash+1,hash+1+tot);
	tot = unique(hash+1,hash+tot+1)-hash-1;
	for (int i=1;i<=n;i++) arr[i] = find(arr[i]);
	for (int i=1;i<=n;i++) rev[i] = find(rev[i]);
	for (int i=1;i<=m;i++) val[i] = find(val[i]);
	
	for (int k=1;k<=n;k++) {
		for (int i=0;i<(int)G[k].size();i++) { if (G[k][i] > 0) CT::modify(G[k][i],val[G[k][i]],1);
			else CT::modify(-G[k][i],val[-G[k][i]],-1);
		}
		int l=1,r=m,ans=0,mn=min(arr[k],rev[k]),mx=max(arr[k],rev[k]);
		ans = CT::GetMX(mn-1,mx-1);
		if (ans) {
			int tmp = CT::query(tot,ans,m) - CT::query(mx-1,ans,m);
			if (tmp % 2) vout += (LL)hash[mn];
			else vout += (LL)hash[mx];
		} else {
			int tmp = CT::query(tot,0,m) - CT::query(mx-1,0,m);
			if (tmp % 2) vout += (LL)hash[rev[k]];
			else vout += (LL)hash[arr[k]];
		}
	}
	printf("%lld\n",vout);
	return 0;
}