在多校前,练练手,发现自己真的好菜。
一开始队友开了签到题,我随便一看看到了M,然后写了一个待修主席树,然后呢大概长这个样子
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
int T;
int n, m;
struct zxs {
int ls[N * 300];
int rs[N * 300];
int tr[N * 300];
ll tr2[N * 300];
int root[N];
int tot = 0;
vector<int>vecl, vecr;
void clear()
{
vecl.clear(); vecr.clear();
tot = 0;
upd(i, 0, N * 290)ls[i] = rs[i] = tr[i] = 0;
upd(i, 0, n)root[i] = 0;
}
int lowbit(int i)
{
return i & (-i);
}
void modify(int &o,int l,int r,int k,int val,int pos)
{
if (!o)o = ++tot;
tr[o] += val;
tr2[o] += 1ll * val * pos;
if (l == r)return;
int mid = (l + r) >> 1;
if (k <= mid)modify(ls[o], l, mid, k, val, pos);
else modify(rs[o], mid + 1, r, k, val, pos);
}
void pre_modify(int x, int k,int val)
{
for (int i = x; i <= n; i += lowbit(i))
modify(root[i], 1, n, k, val,i);
}
int query(int l, int r, int k,int L,int R)
{
if (l == r)return l;
int mid = (l + r) >> 1;
int tsum = 0;
for (auto p : vecr)
{
tsum += 1ll*(R + 1)*tr[ls[p]] - tr2[ls[p]];
}
for (auto p : vecl)
{
tsum -= 1ll*(L + 1)*tr[ls[p]] - tr2[ls[p]];
}
if (tsum >= k)
{
for (int i = 0; i < vecr.size(); i++)vecr[i] = ls[vecr[i]];
for (int i = 0; i < vecl.size(); i++)vecl[i] = ls[vecl[i]];
return query(l, mid, k, L, R);
}
else {
for (int i = 0; i < vecr.size(); i++)vecr[i] = rs[vecr[i]];
for (int i = 0; i < vecl.size(); i++)vecl[i] = rs[vecl[i]];
return query(mid + 1, r, k - tsum, L, R);
}
}
int pre_query(int l, int r, int k)
{
vecl.clear(); vecr.clear();
for (int i = r; i; i -= lowbit(i))vecr.push_back(root[i]);
for (int i = l - 1; i; i -= lowbit(i))vecl.push_back(root[i]);
return query(1, n, k, l, r);
}
int query_v(int l, int r, int k,int L,int R)
{
int tsum = 0;
if (l == r) {
for (auto p : vecr)
tsum += 1ll * (R + 1)*tr[p] - tr2[p];
for (auto p : vecl)
tsum -= 1ll * (L + 1)*tr[p] - tr2[p];
return tsum;
}
int mid = (l + r) >> 1;
if (mid >= k)
{
for (int i = 0; i < vecr.size(); i++)vecr[i] = ls[vecr[i]];
for (int i = 0; i < vecl.size(); i++)vecl[i] = ls[vecl[i]];
return query_v(l, mid, k, L, R);
}
else {
for (int i = 0; i < vecr.size(); i++)vecr[i] = rs[vecr[i]];
for (int i = 0; i < vecl.size(); i++)vecl[i] = rs[vecl[i]];
return query_v(mid + 1, r, k, L, R);
}
}
int pre_val(int l, int r, int k)
{
vecl.clear(); vecr.clear();
for (int i = r; i; i -= lowbit(i))vecr.push_back(root[i]);
for (int i = l - 1; i; i -= lowbit(i))vecl.push_back(root[i]);
return query_v(1, n, k, l, r);
}
}TR;
int main()
{
T = read();
while (T--)
{
n = read(), m = read();
TR.clear();
int u;
upd(i, 1, n)
{
u = read();
TR.pre_modify(i, u, 1);
}
int op, l, r, x, y;
while (m--)
{
op = read();
if(op==1)
{
l = read(), r = read(); x = read(), y = read();
int vv = TR.pre_val(l, r, x);
TR.pre_modify(l, x, -vv);
TR.pre_modify(r + 1, x, vv);
TR.pre_modify(l, y, vv);
TR.pre_modify(r + 1, y, -vv);
}
else {
l = read(), r = read(); x = read();
printf("%d\n", TR.pre_query(l, r, x));
}
}
}
return 0;
}
后来发现分块才是正解。
我是这样想的,询问第k大不用多说,修改的时候,先查找区间里面,x有多少个,然后区间修改,这里使用树状数组的修改方式,记录 s u m [ i ] , i ∗ s u m [ i ] sum[i],i*sum[i] sum[i],i∗sum[i]。
这样的话查询变成 ( p o s + 1 ) ∗ s u m [ i ] − s u m [ i ] ∗ i (pos+1)*sum[i]-sum[i]*i (pos+1)∗sum[i]−sum[i]∗i即可。然而,发现MLE。空间完全承受不住,然后就GG了,用了一个多小时划水。
然后配队友开了H,两个小时过了H。然后又去接着搞D。
最后一个小时写的L。写的时候一开始想用树状数组去解决,然后T了三发(真要吐了)。然后想了暴力求前缀的方式,去维护
题解:
d p [ i ] [ j ] [ 0 ] dp[i][j][0] dp[i][j][0]表示以第i个结尾,另一个串以j结尾,长度为偶数的答案。
d p [ i ] [ j ] [ 1 ] dp[i][j][1] dp[i][j][1]表示以第i个结尾,另一个串以j结尾,长度为奇数的答案。
当且仅当 a [ i ] = = b [ j ] a[i]==b[j] a[i]==b[j]的时候,有转移。
可以发现 d p [ i ] [ j ] [ 0 ] dp[i][j][0] dp[i][j][0]的转移为他前面,所有 a [ k ] < a [ i ] a[k]a[k]<a[i]并且 k < i kk<i转移而来。
同理,奇数相反。故我们令 s u m [ j ] [ 0 ] , s u m [ j ] [ 1 ] sum[j][0],sum[j][1] sum[j][0],sum[j][1]表示 b [ j ] b[j] b[j]的所有偶数\奇数前缀和。当 a [ i ] < b [ j ] a[i]a[i]<b[j]时,说明这个 b [ j ] b[j] b[j]可以作为偶数结尾( a [ i ] = = b [ j ] a[i]==b[j] a[i]==b[j])同理可以推奇数结尾。故我们就能在 o ( n ∗ m ) o(n*m) o(n∗m)的时间内,维护出答案。
总结:自己太菜了
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int T;
const int N = 2e3 + 10;
const int mod = 998244353;
ll a[N], b[N];
int n, m;
ll dp[N][N][10];
ll sum[N][2];
vector<int>vec;
int id[N];
ll add(ll a, ll b)
{
return a + b >= mod ? a + b - mod : a + b;
}
int main()
{
T = read();
while (T--)
{
n = read(), m = read();
upd(i, 0, n)upd(j, 0, m)upd(k, 0, 1)dp[i][j][k] = sum[i][k] = 0;
upd(i, 1, n)a[i] = read(), vec.push_back(a[i]);
upd(i, 1, m)b[i] = read();
ll ans = 0;
upd(i, 1, n)
{
ll cnt0 = 0, cnt1 = 0;
upd(j, 1, m)
{
if (a[i] == b[j])
{
ans = add(cnt1, ans);
ans = add(cnt0 + 1, ans);
dp[i][j][0] = add(cnt1, dp[i][j][0]);
dp[i][j][1] = add(cnt0 + 1, dp[i][j][1]);
}
else if (a[i] < b[j])
{
cnt0 = add(cnt0, sum[j][0]);
}
else {
cnt1 = add(cnt1, sum[j][1]);
}
}
upd(j, 1, m)
{
sum[j][0] = add(sum[j][0], dp[i][j][0]);
sum[j][1] = add(sum[j][1], dp[i][j][1]);
}
}
cout << ans << endl;
}
return 0;
}