题解 区间距离

传送门

  • 关于一类 \(O(\frac{nV}{\omega})\) 计算带偏移量的 \(\sum\limits_{i=l}^r|a_{dlt_1+i}-b_{dlt_2+i}|\) 的方法:
    考虑将一个 \(a-b\) 的贡献拆开,在每个 \(c\in[b, a]\) 都统计一次
    一个做法是把所有数分为 \(<c\)\(\geqslant c\) 的两部分,一个记作 0,另一个记作 1
    那么我们实际上是要求 \(a, b\) 各一个区间的异或的 \(\tt popcount\)
    这个做法还可以优化到 \(O(V(\frac{n^2}{B}+qB))\),方法直接粘题解了
    image
点击查看代码
%:pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 101010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, q;
int a[N], b[N], maxc;

// namespace force{
// 	void solve() {
// 		for (int i=1,p1,p2,x,ans; i<=q; ++i) {
// 			p1=read(); p2=read(); x=read(); ans=0;
// 			for (int j=1; j<=x; ++j) ans+=abs(a[p1+j-1]-b[p2+j-1]);
// 			printf("%d\n", ans);
// 		}
// 	}
// }

// namespace task1{
// 	bitset<N> as[6], bs[6];
// 	void solve() {
// 		for (int c=2; c<=5; ++c) {
// 			for (int i=0; i<n; ++i) if (c<=a[i]) as[c][i]=1;
// 			for (int i=0; i<n; ++i) if (c<=b[i]) bs[c][i]=1;
// 		}
// 		for (int i=1,p1,p2,x,ans; i<=q; ++i) {
// 			p1=read()-1; p2=read()-1; x=read(); ans=0;
// 			for (int c=2; c<=5; ++c) {
// 				ans+=((as[c]>>p1)^(bs[c]>>p2)).count();
// 				ans-=((as[c]>>p1+x)^(bs[c]>>p2+x)).count();
// 			}
// 			printf("%d\n", ans);
// 		}
// 	}
// }

// namespace task2{
// 	const int w=128;
// 	bitset<N> sa[6], sb[6], tem;
// 	bitset<w> aper[6][w][N/w], bper[6][N/w];
// 	int cnt[6][w][N/w][N/w], sum[6][w][N/w][N/w];
// 	void solve() {
// 		// cout<<double(sizeof(aper)+sizeof(bper)+sizeof(cnt)*2)/1000/1000<<endl;
// 		for (int c=2; c<=5; ++c,tem.reset()) {
// 			for (int i=0; i<n; ++i) if (c<=a[i]) sa[c][i]=tem[i]=1;
// 			for (int dlt=0; dlt<w; ++dlt,tem<<=1) {
// 				tem=sa[c]<<dlt;
// 				// cout<<"tem: "<<tem<<endl;
// 				for (int l=0,r,id=0; l<n+w; l=r+1,++id) {
// 					r=l+w-1;
// 					// cout<<"lr: "<<l<<' '<<r<<endl;
// 					for (int j=l; j<=r; ++j) aper[c][dlt][id][j-l]=tem[j];
// 					// cout<<"aper: "<<aper[c][dlt][id]<<endl;
// 				}
// 			}
// 		}
// 		for (int c=2; c<=5; ++c) {
// 			for (int i=0; i<n; ++i) if (c<=b[i]) sb[c][i]=1;
// 			for (int l=0,r,id=0; l<n; l=r+1,++id) {
// 				r=l+w-1;
// 				// cout<<"id: "<<l<<' '<<r<<' '<<id<<endl;
// 				for (int j=l; j<=r; ++j) bper[c][id][j-l]=sb[c][j];
// 			}
// 		}
// 		for (int c=2; c<=5; ++c)
// 			for (int dlt=0; dlt<w; ++dlt)
// 				for (int i=0; i<=(n+w)/w; ++i)
// 					for (int j=0; j<=n/w; ++j)
// 						cnt[c][dlt][i][j]=(aper[c][dlt][i]^bper[c][j]).count();
// 		for (int c=2; c<=5; ++c)
// 			for (int dlt=0; dlt<w; ++dlt)
// 				for (int i=0; i<=(n+w)/w; ++i)
// 					for (int j=0; j<=n/w; ++j)
// 						sum[c][dlt][i][j]=(i&&j?sum[c][dlt][i-1][j-1]:0)+cnt[c][dlt][i][j];
// 		for (int i=1,p1,p2,x,ans; i<=q; ++i) {
// 			p1=read()-1; p2=read()-1; x=read(); ans=0;
// 			// if (x<w) {for (int j=0; j<x; ++j) ans+=abs(a[p1+j]-b[p2+j]); printf("force: %d\n", ans); continue;}
// 			if (x<w) {for (int j=0; j<x; ++j) ans+=abs(a[p1+j]-b[p2+j]); printf("%d\n", ans); continue;}
// 			int ida=p1%w, idb=p2%w, dlt;
// 			// cout<<"p: "<<p1<<' '<<p2<<endl;
// 			// cout<<"x: "<<x<<endl;
// 			// cout<<"rest: "<<ida<<' '<<idb<<endl;
// 			if (ida<=idb) dlt=idb-ida;
// 			else dlt=w+idb-ida;
// 			// cout<<"dlt: "<<dlt<<endl;
// 			for (int c=2; c<=5; ++c) {
// 				// for (int j=0; j<x; ++j) ans+=sa[c][p1+j]^sb[c][p2+j]; continue;
// 				for (int j=0; j<w-idb; ++j) ans+=sa[c][p1+j]^sb[c][p2+j];
// 				// cout<<"w-idb: "<<w-idb<<endl;
// 				int pos1=(p1+dlt)/w+1, pos2=p2/w+1;
// 				// cout<<"pos: "<<pos1<<' '<<pos2<<endl;
// 				int lim=(x-w+idb)/w;
// 				// cout<<"lim: "<<(x-w+idb)/w<<endl;
// 				// for (int j=1; j<=(x-w+idb)/w; ++j,++pos1,++pos2) {
// 				// 	// cout<<"j: "<<j<<endl;
// 				// 	// bitset<N> tem=sa[c]<<dlt; int val=0;
// 				// 	// for (int k=0; k<w; ++k) ans+=tem[w*pos1+k]^sb[c][w*pos2+k], val+=tem[w*pos1+k]^sb[c][w*pos2+k];
// 				// 	// for (int k=w-1; ~k; --k) cout<<tem[w*pos1+k]; cout<<' ';
// 				// 	// for (int k=w-1; ~k; --k) cout<<sb[c][w*pos2+k]; cout<<endl;
// 				// 	// cout<<"val: "<<val<<endl;
// 				// 	ans+=cnt[c][dlt][pos1][pos2]; //, cout<<cnt[c][dlt][pos1][pos2]<<endl;
// 				// 	// cout<<"cnt: "<<cnt[c][dlt][pos1][pos2]<<endl;
// 				// 	// cout<<aper[c][dlt][pos1]<<' '<<bper[c][pos2]<<endl;
// 				// 	// ans+=(aper[c][dlt][pos1]^bper[c][pos2]).count();
// 				// }
// 				ans+=sum[c][dlt][pos1+lim-1][pos2+lim-1]-(pos1&&pos2?sum[c][dlt][pos1-1][pos2-1]:0);
// 				// cout<<"now: "<<w*((x-w+idb)/w)+w-idb<<endl;
// 				for (int now=w*((x-w+idb)/w)+w-idb; now<x; ++now) ans+=sa[c][p1+now]^sb[c][p2+now]; //, cout<<now<<' '<<(int)(sa[c][p1+now]^sb[c][p2+now])<<endl;
// 			}
// 			printf("%d\n", ans);
// 		}
// 	}
// }

namespace task{
	const int w=170, len=300;
	bitset<N> sa, sb, tem;
	int p1[N*10], p2[N*10], x[N*10];
	bitset<w> aper[w][N/w+10], bper[N/w+10];
	int cnt[w][N/w+10][N/w+10], sum[w][N/w+10][N/w+10], ans[N*10];
	void solve() {
		// cout<<double(sizeof(aper)+sizeof(bper)+sizeof(cnt)*2)/1000/1000<<endl; exit(0);
		for (int i=1; i<=q; ++i) {
			p1[i]=read()-1, p2[i]=read()-1, x[i]=read();
			if (x[i]<len) {for (int j=0; j<x[i]; ++j) ans[i]+=abs(a[p1[i]+j]-b[p2[i]+j]);}
		}
		for (int c=2; c<=maxc; ++c) {
			sa.reset(), sb.reset(), tem.reset();
			for (int i=0; i<n; ++i) if (c<=a[i]) sa[i]=tem[i]=1;
			for (int dlt=0; dlt<w; ++dlt,tem<<=1) {
				for (int l=0,r,id=0; l<n+w; l=r+1,++id) {
					r=l+w-1;
					for (int j=l; j<=r; ++j) aper[dlt][id][j-l]=tem[j];
				}
			}
			for (int i=0; i<n; ++i) if (c<=b[i]) sb[i]=1;
			for (int l=0,r,id=0; l<n; l=r+1,++id) {
				r=l+w-1;
				for (int j=l; j<=r; ++j) bper[id][j-l]=sb[j];
			}
			for (int dlt=0; dlt<w; ++dlt)
				for (int i=0; i<=(n+w)/w; ++i)
					for (int j=0; j<=n/w; ++j)
						cnt[dlt][i][j]=(aper[dlt][i]^bper[j]).count();
			for (int dlt=0; dlt<w; ++dlt)
				for (int i=0; i<=(n+w)/w; ++i)
					for (int j=0; j<=n/w; ++j)
						sum[dlt][i][j]=(i&&j?sum[dlt][i-1][j-1]:0)+cnt[dlt][i][j];
			for (int i=1,p1,p2,x,ans; i<=q; ++i) {
				p1=task::p1[i]; p2=task::p2[i]; x=task::x[i]; ans=0;
				if (x<len) continue;
				int ida=p1%w, idb=p2%w, dlt;
				if (ida<=idb) dlt=idb-ida;
				else dlt=w+idb-ida;
				for (int j=0; j<w-idb; ++j) ans+=sa[p1+j]^sb[p2+j];
				int pos1=(p1+dlt)/w+1, pos2=p2/w+1;
				int lim=(x-w+idb)/w;
				ans+=sum[dlt][pos1+lim-1][pos2+lim-1]-(pos1&&pos2?sum[dlt][pos1-1][pos2-1]:0);
				for (int now=w*((x-w+idb)/w)+w-idb; now<x; ++now) ans+=sa[p1+now]^sb[p2+now];
				task::ans[i]+=ans;
			}
		}
		for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);
	}
}

signed main()
{
	freopen("dist.in", "r", stdin);
	freopen("dist.out", "w", stdout);

	n=read(); q=read();
	for (int i=0; i<n; ++i) maxc=max(maxc, a[i]=read());
	for (int i=0; i<n; ++i) maxc=max(maxc, b[i]=read());
	// force::solve();
	// task1::solve();
	task::solve();

	return 0;
}
posted @ 2022-06-22 07:19  Administrator-09  阅读(3)  评论(0编辑  收藏  举报