Codeforces 654F Paper task (sam+bit)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <ctime>
#include <functional>
#pragma comment(linker,"/STACK:102400000,102400000")
using namespace std;


#define eps 1e-10
#define N 2000020
#define B 20
#define M 3000020
#define inf 0x3f3f3f3f
#define LL long long
#define pii pair<int, int>
#define MP make_pair
#define fi first
#define se second
#define mod 1000000007

#define md (ll + rr >> 1)


char str[N];
int s[N];
int R[N];
int n;
int san[N], cnt;
int mi[N];
int id[N];
int sum[N];

struct query1 {
	int l, r, x, v;
	query1() {}
	query1(int l, int r, int x, int v):l(l), r(r), x(x), v(v) {}
	bool operator < (const query1 &b) const {
		return x > b.x;
	}
}b[N];
int q1;

struct sam {
	int ch[N][2], par[N], val[N], rr[N];
	int tot, lst;
	int num[N], topo[N];

	int creat(int v) {
		int k = ++tot;
		ch[k][0] = ch[k][1] = par[k] = 0;
		val[k] = v;
		rr[k] = 0;
		return k;
	}
	void init() {
		tot = 0;
		lst = creat(0);
	}
	void extend(int c, int r) {
		int p = lst;
		int np = creat(val[p] + 1);
		rr[np] = r;
		while(p && ch[p][c] == 0) ch[p][c] = np, p = par[p];
		if(!p) par[np] = 1;
		else {
			int q = ch[p][c];
			if(val[q] == val[p] + 1) par[np] = q;
			else {
				int nq = creat(val[p] + 1);
				memcpy(ch[nq], ch[q], sizeof ch[q]);
				par[nq] = par[q];
				par[q] = par[np] = nq;
				while(p && ch[p][c] == q) ch[p][c] = nq, p = par[p];
			}
		}
		lst = np;
	}
	void get_rr() {
		for(int i = 0; i <= tot; ++i) num[i] = 0;
		for(int i = 1; i <= tot; ++i) num[val[i]]++;
		for(int i = 1; i <= tot; ++i) num[i] += num[i - 1];
		for(int i = tot; i >= 1; --i) topo[num[val[i]]--] = i;

		for(int i = tot; i >= 2; --i) {
			int u = topo[i];
			rr[par[u]] = max(rr[par[u]], rr[u]);
		}
	}
	void get_query1() {
		q1 = 0;
		for(int i = 2; i <= tot; ++i) {
			b[++q1] = query1(rr[i] - val[i] + 1, rr[i] - (val[par[i]] + 1) + 1, rr[i], s[rr[i]]);
		}
	}


}s_auto;

struct query2 {
	int type, l, r, v, t;
	query2() {}
	query2(int type, int l, int r, int v, int t):type(type), l(l), r(r), v(v), t(t) {}

	bool operator < (const query2 &b) const {
		if(v != b.v) return v < b.v;
		return t < b.t;
	}

}c[N];
int q2;
int haxi(int x) {
	return lower_bound(san + 1, san + cnt + 1, x) - san;
}

void bit_update(int x, int v) {
	while(x <= cnt) {
		mi[x] = min(mi[x], v);
		x += x & -x;
	}
}
int bit_query(int x) {
	int ret = inf;
	while(x) {
		ret = min(ret, mi[x]);
		x -= x & -x;
	}
	return ret;
}


void get_R() {
	cnt = 0;
	for(int i = 0; i <= n; ++i) san[++cnt] = s[i];
	sort(san + 1, san + cnt + 1);
	cnt = unique(san + 1, san + cnt + 1) - san - 1;
	for(int i = 1; i <= cnt; ++i) mi[i] = inf;
	for(int i = n; i >= 1; --i) {
		int p = haxi(s[i]);
		bit_update(p, i);
		p = haxi(s[i - 1]);
		int tmp_id = bit_query(p - 1);
		if(tmp_id != inf) R[i] = tmp_id - 1;
		else R[i] = n;
	}
}

bool cmp_by_R(int i, int j) {
	return R[i] > R[j];
}

void get_query2() {
	int j = 1;
	q2 = 0;
	int tid = 0;
	for(int i = 1; i <= q1; ++i) {
		while(j <= n) {
			int u = id[j];
			if(R[u] >= b[i].x) {
				c[++q2] = query2(0, u, -1, s[u - 1], ++tid);
				++j;
			}
			else break;
		}
		
		c[++q2] = query2(2, b[i].l, b[i].r, s[b[i].x], ++tid);
	}
}

int query_sum(int x) {
	int ret = 0;
	while(x) {
		ret += sum[x];
		x -= x & -x;
	}
	return ret;
}
void add(int x, int v) {
	while(x <= n) {
		sum[x] += v;
		x += x & -x;
	}
}

int main() {	
	scanf("%d", &n);
	scanf("%s", str + 1);
	for(int i = 1; i <= n; ++i) {
		if(str[i] == '(') s[i] = s[i - 1] + 1;
		else s[i] = s[i - 1] - 1;
	}
	get_R();

	s_auto.init();
	for(int i = 1; i <= n; ++i) {
		int c;
		if(str[i] == '(') c = 0;
		else c = 1;
		s_auto.extend(c, i);
	}
	s_auto.get_rr();
	s_auto.get_query1();
	sort(b + 1, b + q1 + 1);
	for(int i = 1; i <= n; ++i) id[i] = i;

	sort(id + 1, id + n + 1, cmp_by_R);

	get_query2();
	LL ans = 0;
	sort(c + 1, c + q2 + 1);

	for(int i = 1; i <= q2; ++i) {
		int j = i;
		while(j <= q2 && c[j].v == c[i].v) ++j;
		--j;
		for(int k = i; k <= j; ++k) {
			if(c[k].type == 0) add(c[k].l, 1);
			else ans += query_sum(c[k].r) - query_sum(c[k].l - 1);
		}
		for(int k = i; k <= j; ++k) {
			if(c[k].type == 0) add(c[k].l, -1);
		}
		i = j;
	}
	cout << ans << endl;
	return 0;
}





	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值