点击查看代码
//模板集合
/*所有private首字母大写 ,所有public接口全小写*/
#pragma GCC optimize("Ofast")
#define LOCAL
#define BIT
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double db;
typedef long double ldb;
typedef string str;
#define mem(a,b) memset(a, b, sizeof a)
#define debug(x) cerr << #x << '=' << x <<' '
//#define int ll
//#define double ldb
int n, m;
const int N = 5010, M = 20010, MOD = 1e9 + 7;
const int base = 1e8;//进制
const int INF = 1e9;//极大值
template<typename T>T max(T a, T b, T c) {return max(max(a, b), c);}
template<typename T>T min(T a, T b, T c) {return min(min(a, b), c);}
#ifdef BIT//位运算奇技淫巧
#define lowbit(x) ((x) & (-(x)))
#define bin(i) (1 << (i))//生成一个只有第i位为1,其余位为0的数(2^i))
#define set_bit(x, i) ((x) | bin(i))//将第i位设置为1
#define clr_bit(x, i) ((x) & (~ bin(i)))//将第i位设置为0
#define flip_bit(x, i) ((x) ^ bin(i))//切换x的第i位的状态
#define get_bit(x, i) (((x) >> (i)) & 1)//x的第i位的值
#define check_adjacent_1(x) ((x) & ((x) >> 1))//检查是否有相邻的1
int count_bit(int x)
{
int sum = 0;
while(x)
{
x &= (x - 1);//清除最低位的1
++sum;
}
return sum;
}
#endif
namespace IO
{
#ifndef LOCAL
const int Z = 1 << 20;
char buf[Z], *p1 = buf, *p2 = buf, obuf[Z], *p3 = obuf;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, Z, stdin), p1 == p2) ? EOF : *p1++)
#define flush() (fwrite(obuf, p3-obuf, 1, stdout))
#define pc(x) ((p3-obuf < Z) ? (*p3++ = x) : (flush(), p3 = obuf , *p3++ = x))
class Flush {public: ~Flush() {flush();}} _;
#else
#define gc() getchar()
#define pc(x) putchar(x)
#endif
char re(char &c) {do c = gc(); while(isspace(c)); return c;}
void write(const char c) {pc(c);}
void re(char *c) {char ch; re(ch); do *(c++) = ch; while(!isspace(ch = gc())); *c = '\0';}
void write(const char *c) {while(*c) pc(*(c++));}
str re(str &s) {char ch[100]; re(ch), s = ch; return s;}
void write(const str s) {int len = s.length(); for(int i = 0; i < len; ++i) pc(s[i]);}
template<typename t1>t1 re(t1 &x) {x = 0; bool f = false; char c = gc(); while(!isdigit(c)) f ^= (c == '-'), c = gc(); while(isdigit(c)) x = (x << 1) + (x << 3) + c - '0', c = gc(); return f ? x = -x : x;}
template<typename t1>void write(t1 x) {x < 0 ? x = -x, pc('-') : 0; short Stack[65], top = 0; do Stack[++top] = x % 10, x /= 10; while(x > 0); while(top) pc(Stack[top--] + '0');}
template<typename t1, typename ...t2>void re(t1 &x, t2 &...y) {re(x), re(y...);}
template<typename t1, typename ...t2>void write(t1 x, t2...y) {write(x), pc(' '), write(y...), pc(' ');}
};
class STL
{
int a;
void Vector()
{
vector<int> v(N, -1);
v.begin(), v.end();//返回vector的首、尾迭代器
v.front(), v.back();//返回vector的首、尾元素
v.push_back(a);//从vector末尾加入一个元素
v.size();//返回vector当前的长度(大小)
v.pop_back();//从vector末尾删除一个元素
v.empty();//返回vector是否为空,1为空、0不为空
v.clear();//清空vector
v.max_size();//输出vector最大容量
v.capacity();//输出vector真实大小 ,类似size
v.insert(v.begin() + 1, 1);//插入操作,第一个参数是指针类型,第二个参数是插入对象
v.erase(v.begin());//删除指定位置的数据
sort(v.begin(), v.end());
}
void Queue()
{
queue<int> q;
q.front(), q.back();//返回queue的首、尾元素
q.push(a);//从queue末尾加入一个元素
q.size();//返回queue当前的长度(大小)
q.pop();//从queue末尾删除一个元素
q.empty();//返回queue是否为空,1为空、0不为空
}
void Stack()
{
stack<int> st;
st.top();//返回stack的栈顶元素
st.push(a);//从stack栈顶加入一个元素
st.size();//返回stack当前的长度(大小)
st.pop();//从stack栈顶弹出一个元素
st.empty();//返回stack是否为空,1为空、0不为空
}
void Priority_queue()
{
priority_queue<int> p;
priority_queue<int, vector<int>, greater<int> > q;
p.top();//返回priority_queue的首元素
p.push(a);//向priority_queue中加入一个元素
p.size();//返回priority_queue当前的长度(大小)
p.pop();//从priority_queue末尾删除一个元素
p.empty();//返回priority_queue是否为空,1为空、0不为空
}
void Deque()
{
deque<int> de;
de.begin(), de.end();//返回deque的首、尾迭代器
de.front(), de.back();//返回deque的首、尾元素
de.push_back(a);//从队尾入队一个元素
de.push_front(a);//从队头入队一个元素
de.pop_back();//从队尾出队一个元素
de.pop_front();//从队头出队一个元素
de.clear();//清空队列
}
void Set()
{
set<int> s;
s.empty();//返回当前集合是否为空,是返回1,否则返回0.
s.size();//返回当前集合的元素个数。
s.clear();//清空当前集合。
s.begin(), s.end();//回集合的首尾迭代器。
s.insert(a);//表示向集合中加入元素a
s.erase(a);//表示删除集合中元素a
s.find(a);//返回集合中指向元素a的迭代器。如果不存在这个元素,就返回s.end(),这个性质可以用来判断集合中有没有这个元素。
s.lower_bound(a), s.upper_bound(a);//返回集合中第一个大于等于关键字的元素。返回集合中第一个严格大于关键字的元素。
}
void Bitset()
{
bitset<100> b;
b.count();//返回b中有多少个1
b.any(), b.none();//如果,bitset中全都为0,那么any返回0,none()返回1;
//反之,假如bitset中至少有一个1,那么any返回1,none返回0
b.set();//把bitset全部置为1
b.set(a, 1);//把a位置置为1
b.reset();//把bitset全部置为0
b.reset(a);//把a位置置为0
b.flip();//把bitset全部取反
b.flip(a);//把a位置取反
}
void Map()
{
map<int, int> mp, mp1;
mp.insert(pair<int, int>(1, 1));//插入
mp.find(a);//返回键是a的映射的迭代器
mp.clear();//清空
mp.erase(a);//删除一个元素
mp.erase(mp.begin(), mp.end());
mp.size();//长度
mp.begin(), mp.end();//返回指向map头部末尾的迭代器
mp.empty();//判断其是否为空
swap(mp, mp1);//交换两个map
}
};
struct Chain_Forward_Star//链式前向星
{
struct edge
{
int v, w, nxt;//终点,权值,下一条边的编号
} e[M << 1];
int head[N], idx;
Chain_Forward_Star() {clear();}
void clear()
{
idx = 0;
memset(head, -1, sizeof head);
}
void add_edge(int u, int v, int w = 1)//加边
{
e[++idx] = {v, w, head[u]};
head[u] = idx;
}
};
class Union_Find//并查集
{
public:
Union_Find() {clear();}
void clear(int n_ = N - 1)
{
for(int i = 0; i <= n_; ++i)
fa[i] = i, size[i] = 1;
}
int find(int x)//找最大祖先
{
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
bool merge(int x, int y)//合并,成功返回1,失败返回0
{
x = find(x), y = find(y);
if(x == y) return false;
if(size[x] < size[y]) swap(x, y);
fa[y] = x;
size[x] += size[y];
size[y] = 0;
return true;
}
bool query(int x, int y)//查询是否在统一集合
{
return find(x) == find(y);
}
int get_size(int x)//查询所在集合的大小
{
return size[find(x)];
}
private:
int fa[N], size[N];
};
struct Dijkstra//最短路
{
Chain_Forward_Star C;
int dis[N], dis1[N];//距离
bool vis[N];//标记
struct node
{
int name, dis;
bool operator <(const node &x) const
{
return x.dis < dis;
}
};
void dijkstra(int s)//最短路
{
memset(dis, 0x3f, sizeof dis);//初始化为最大值
dis[s] = 0;
priority_queue<node> pq;
pq.push(node{s, 0});
while(!pq.empty())
{
node tmp = pq.top();
pq.pop();
int u = tmp.name;
if(vis[u]) continue;
vis[u] = true;
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v, w = C.e[i].w;
if(dis[u] + w < dis[v])
{
dis[v] = dis[u] + w;
if(!vis[v])
pq.push(node{v, dis[v]});
}
}
}
}
void dijkstra1(int s)//严格次短路
{
memset(dis, 0x3f, sizeof dis);
memset(dis1, 0x3f, sizeof dis1);
dis[s] = 0;
priority_queue<node> pq;
pq.push(node{s, 0});
while(!pq.empty())
{
node tmp = pq.top();
pq.pop();
int u = tmp.name;
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v, w = C.e[i].w;
if(dis[u] + w < dis[v])
{
dis1[v] = dis[v];
dis[v] = dis[u] + w;
pq.push(node{v, dis[v]});
pq.push(node{v, dis1[v]});
}
else
{
if(dis[u] + w < dis1[v] && dis[v] != dis[u] + w)
{
dis1[v] = dis[u] + w;
pq.push(node{v, dis[v]});
pq.push(node{v, dis1[v]});
}
else if(dis1[u] + w < dis1[v] && dis1[u] + w != dis[v])
{
dis1[v] = dis1[u] + w;
pq.push(node{v, dis[v]});
pq.push(node{v, dis1[v]});
}
}
}
}
}
};
class Binary_Index_Tree//树状数组
{
public:
Binary_Index_Tree() {clear();}
void clear() {memset(t, 0, sizeof t);}
void add(int x, int v)//将x的位置加上v
{
while(x <= n)
{
t[x] += v;
x += lowbit(x);
}
}
int sum(int x)//1~x的和
{
int res = 0;
while(x)
{
res += t[x];
x -= lowbit(x);
}
return res;
}
int query(int l, int r)//查询l~r的区间和
{
return sum(r) - sum(l - 1);
}
private:
int t[N];
};
struct Quick//快速算法
{
ll qpow(ll a, ll b)//快速幂
{
ll res = 1;
a %= MOD;
while(b)
{
if(b & 1) res = (res * a) % MOD;
a = (a * a) % MOD;
b >>= 1;
}
return res;
}
ll qmul(ll a, ll b)//快速乘
{
ll res = 0;
a %= MOD;
while(b)
{
if(b & 1) res = (res + a) % MOD;
a = (a + a) % MOD;
b >>= 1;
}
return res;
}
int exgcd(int a, int b, int &x, int &y)//返回gcd,x,y为ax+by=gcd(a,b)的一组可行解
{
if(!b)
{
x = 1, y = 0;
return a;
}
int gcd = exgcd(b, a % b, x, y);
int t = x;
x = y, y = t - a / b * y;
return gcd;
}
void exgcd1(int a, int b, int &x, int &y)
{
if(!b) x = 1, y = 0;
else
{
exgcd1(b, a % b, y, x);
y -= a / b * x;
}
}
};
struct Least_Common_Ancestors//最近公共祖先
{
Chain_Forward_Star C;
int depth[N];//深度
int dis[N];//到根节点的距离
int Log2[N];
int fa[N][22];//fa[i][j]为i的(2^j)的父亲
Least_Common_Ancestors(int n_ = N - 1)
{
Log2[0] = Log2[1] = 0;
for(int i = 2; i <= n_; ++i)
Log2[i] = Log2[i >> 1] + 1;
}
void dfs(int now, int f, int len)//当前,父亲,边的长度
{
depth[now] = depth[f] + 1;
fa[now][0] = f;
dis[now] = dis[f] + len;
for(int i = 1; i <= 21; ++i)
fa[now][i] = fa[fa[now][i - 1]][i - 1];
for(int i = C.head[now]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v, w = C.e[i].w;
if(v == f) continue;
dfs(v, now, w);
}
}
int lca(int x, int y)//最近公共祖先
{
if(x == y) return x;
if(depth[x] < depth[y]) swap(x, y);
int s = Log2[depth[x] - depth[y]];
while(s >= 0)
{
if(depth[fa[x][s]] >= depth[y])
x = fa[x][s];
--s;
}
if(x == y) return x;
s = Log2[depth[x]];
while(s >= 0)
{
if(fa[x][s] != fa[y][s])
{
x = fa[x][s];
y = fa[y][s];
}
--s;
}
return fa[x][0];
}
int query(int x, int y)
{
int Lca = lca(x, y);
return dis[x] + dis[y] - (dis[Lca] << 1);
}
};
struct Difference_Constraint//差分约束
{
Chain_Forward_Star C;
int dis[N];//距离
int cnt[N];//入队次数
bool in_queue[N];//是否在队列里
bool spfa(int s)//返回1则有负环
{
memset(dis, 0x3f, sizeof dis);
dis[s] = 0;
queue<int> q;
in_queue[s] = true;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
in_queue[u] = false;
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v, w = C.e[i].w;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if(!in_queue[v])
{
++cnt[v];
if(cnt[v] > n + 1) return true;
q.push(v);
in_queue[v] = true;
}
}
}
}
return false;
}
};
struct Kruskal//最小生成树
{
struct edge
{
int u, v, w;
bool operator <(const edge &x) const
{
return w < x.w;
}
} e[M];
Union_Find U;
int kruskal()
{
int tot = 0;//已经选了多少条边
int res = 0;
sort(e + 1, e + m + 1);
for(int i = 1; i <= m; ++i)
if(U.merge(e[i].u, e[i].v))
{
res += e[i].w;
++tot;
if(tot == n - 1) break;
}
if(tot != n - 1) return -1;
return res;
}
};
struct Prim//最小生成树
{
Chain_Forward_Star C;
int dis[N];
bool vis[N];
struct node
{
int name, dis;
bool operator < (const node &x) const
{
return x.dis < dis;
}
};
int prim()
{
priority_queue<node> pq;
int res = 0, tot = 0;//最小生成树边数
memset(dis, 0x3f, sizeof dis);
dis[1] = 0;
pq.push(node{1, 0});
while(tot < n && !pq.empty())//边数=点数-1
{
node tmp = pq.top();
pq.pop();
int u = tmp.name;
if(vis[u]) continue;
vis[u] = true;
++tot;
res += tmp.dis;
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v, w = C.e[i].w;
if(!vis[v] && dis[v] > w)
{
dis[v] = w;
pq.push(node{v, w});
}
}
}
if(tot < n) return -1;//不连通
return res;
}
};
struct Hungarian_Algorithm//二分图最大匹配匈牙利算法
{
Chain_Forward_Star C;
int marry[N];
bool vis[N];
bool dfs(int u)
{
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v;
if(vis[v]) continue;
vis[v] = true;
if(!marry[v] || dfs(marry[v]))
{
marry[v] = u;
return true;
}
}
return false;
}
int find_max_matching()
{
int matching = 0;
for(int i = 1; i <= n; ++i)
{
memset(vis, false, sizeof vis);
if(dfs(i)) ++matching;
}
return matching;
}
};
struct Topological_Sorting//拓扑排序
{
int in[N];
int res[N], cnt;
Chain_Forward_Star C;
Topological_Sorting(): cnt(0) {}
bool topo()//返回1有环,返回0无环
{
queue<int> q;
for(int i = 1; i <= n; ++i)
if(in[i] == 0)
{
q.push(i);
res[++cnt] = i;
}
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v;
--in[v];
if(in[v] == 0)
{
q.push(v);
res[++cnt] = v;
}
}
}
if(cnt < n) return true;
return false;
}
};
struct Knuth_Morris_Pratt//KMP字符串匹配
{
int n, m;//n=lena,m=lenb
int fail[N], f[N];
int res;//a在b中出现的次数
char a[N], b[N];
Knuth_Morris_Pratt(): n(0), m(0), res(0) {}
void kmp()
{
fail[1] = 0;
for(int i = 2, j = 0; i <= n; ++i)
{
while(j > 0 && a[i] != a[j + 1])
j = fail[j];
if(a[i] == a[j + 1]) ++j;
fail[i] = j;
}
for(int i = 1, j = 0; i <= m; ++i)
{
while(j > 0 && (j == n || b[i] != a[j + 1]))
j = fail[j];
if(b[i] == a[j + 1]) ++j;
f[i] = j;
if(f[i] == n) ++res;
}
}
};
struct Tarjan_Strong_Connectivity_Component//强联通分量
{
Chain_Forward_Star C;
int dfn[N], low[N], timestamp;
stack<int> stk;
bool in_stk[N];
int scc[N], scc_cnt, scc_size[N];
Tarjan_Strong_Connectivity_Component(): timestamp(0), scc_cnt(0) {}
void tarjan(int u)
{
dfn[u] = low[u] = ++timestamp;
stk.push(u);
in_stk[u] = true;
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(in_stk[v])
low[u] = min(low[u], low[v]);
}
if(dfn[u] == low[u])
{
++scc_cnt;
while(stk.top() != u)
{
scc[stk.top()] = scc_cnt;
++scc_size[scc_cnt];
in_stk[stk.top()] = false;
stk.pop();
}
scc[stk.top()] = scc_cnt;
++scc_size[scc_cnt];
in_stk[stk.top()] = false;
stk.pop();
}
}
};
struct Tarjan_Cutvtex//割点
{
Chain_Forward_Star C;
int dfn[N], low[N], timestamp;
bool cutvertex[N];//是否是割点
int res;//割点数
Tarjan_Cutvtex(): timestamp(0), res(0) {}
void tarjan(int u, int fa)
{
dfn[u] = low[u] = ++timestamp;
int son = 0;
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v;
if(!dfn[v])
{
++son;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(fa != u && low[v] >= dfn[u] && son && !cutvertex[u])
{
cutvertex[u] = true;
++res;
}
}
else if(v != fa)
low[u] = min(low[u], dfn[v]);
}
if(fa == u && son >= 2 && !cutvertex[u])
{
cutvertex[u] = true;
++res;
}
}
};
struct Int//高精度
{
int num[N];
Int(int x = 0): num()
{
for(int i = x; i; i /= base)
num[++num[0]] = i % base;
if(!num[0]) ++num[0];
}
void re()
{
num[0] = 0;
char c = getchar();
while(c < '0' || c > '9')
c = getchar();
while(c >= '0' && c <= '9')
num[++num[0]] = (c - '0'), c = getchar();
reverse(num + 1, num + num[0] + 1);
//压位
// char c[N];
// scanf("%s",c);
// int lenc = strlen(c);
// num[0] = 1;
// for(int r = lenc - 1,l = 0; r >= 0; r = l - 1)
// {
// l = r - 8 + 1;
// if(l < 0)
// l = 0;
// for(int i = l; i <= r; ++i)
// num[num[0]] = (num[num[0]] * 10) + (c[i] - '0');
// ++num[0];
// }
// --num[0];
}
void write()
{
for(int i = num[0]; i >= 1; --i)
putchar(num[i] + '0');
putchar('\n');
//压位
// while (num[0] && !num[num[0]]) --num[0];
// printf("%lld",num[num[0]]);
// for(int i = num[0] - 1; i >= 1; --i)
// printf("%08lld",num[i]);
// printf("\n");
}
Int operator + (const Int &b)
{
Int c;
c.num[0] = max(num[0], b.num[0]);
for(int i = 1; i <= c.num[0]; ++i)
{
c.num[i] += num[i] + b.num[i];
c.num[i + 1] += c.num[i] / base;
c.num[i] %= base;
}
if(c.num[c.num[0] + 1])
++c.num[0];
return c;
}
Int operator - (const Int &b)
{
Int c;
c.num[0] = max(num[0], b.num[0]);
int jiewei = 0;
for(int i = 1; i <= c.num[0]; ++i)
{
c.num[i] = num[i] - b.num[i] - jiewei;
if(c.num[i] < 0)
c.num[i] += base, jiewei = 1;
else jiewei = 0;
}
while(c.num[0] > 1 && !c.num[c.num[0]])
--c.num[0];
return c;
}
Int operator * (const Int &b)
{
Int c;
c.num[0] = num[0] + b.num[0];
for(int i = 1; i <= num[0]; ++i)
for(int j = 1; j <= b.num[0]; ++j)
{
c.num[i + j - 1] += num[i] * b.num[j];
c.num[i + j] += c.num[i + j - 1] / base;
c.num[i + j - 1] %= base;
}
while(c.num[0] > 1 && !c.num[c.num[0]])
--c.num[0];
return c;
}
Int operator / (int k)
{
Int c;
c.num[0] = num[0];
int x = 0;
for(int i = num[0]; i >= 1; --i)
{
x = x * base + num[i];
c.num[i] = x / k;
x %= k;
}
while(c.num[0] > 1 && !c.num[c.num[0]])
--c.num[0];
return c;
}
};
bool operator < (const Int &a, const Int &b)
{
if(a.num[0] != b.num[0])
return a.num[0] < b.num[0];
for(int i = a.num[0]; i >= 1; --i)
if(a.num[i] != b.num[i])
return a.num[i] < b.num[i];
return false;
}
bool operator > (const Int &a, const Int &b) {return b < a;}
bool operator <= (const Int &a, const Int &b) {return !(a > b);}
bool operator >= (const Int &a, const Int &b) {return !(a < b);}
Int gcd(Int a, Int b)
{
if(a < b) swap(a, b);
int r = 0;//2的次数
while(b > 0)
{
if(a.num[1] % 2 == 0 && b.num[1] % 2 == 0)
a = a / 2, b = b / 2, ++r;
else if(a.num[1] % 2 == 0 && b.num[1] % 2 != 0)
a = a / 2;
else if(a.num[1] % 2 != 0 && b.num[1] % 2 == 0)
b = b / 2;
else a = (a - b) / 2;
if(a < b) swap(a, b);
}
for(int i = 1; i <= r; ++i)
a = a * 2;
return a;
}
struct Prime_Sieve//线性筛素数
{
bool not_prime[N];
int prime[N];
void make_prime()
{
prime[0] = 0;
not_prime[1] = true;
for(int i = 2; i <= n; ++i)
{
if(!not_prime[i])
prime[++prime[0]] = i;
for(int j = 1; j <= prime[0] && i * prime[j] <= n; ++j)
{
not_prime[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
}
}
}
};
struct Matrix//矩阵
{
ll a[N][N];
ll n, m;//行数,列数
Matrix(int n_ = 0, int m_ = 0): n(n_), m(m_)
{
for(int i = 1; i <= n_; ++i)
for(int j = 1; j <= m_; ++j)
a[i][j] = 0;
}
void re()
{
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
cin >> a[i][j];
}
void write()
{
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
cout << a[i][j] << ' ';
cout << '\n';
}
}
Matrix operator + (const Matrix &B)
{
Matrix res(n, m);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
res.a[i][j] = a[i][j] + B.a[i][j];
return res;
}
Matrix operator - (const Matrix &B)
{
Matrix res(n, m);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
res.a[i][j] = a[i][j] - B.a[i][j];
return res;
}
void operator *=(const ll &k)
{
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
a[i][j] *= k;
}
Matrix operator * (const Matrix &B)
{
Matrix res(n, B.m);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= B.m; ++j)
{
res.a[i][j] = 0;
for(int k = 1; k <= m; ++k)
res.a[i][j] += a[i][k] * B.a[k][j];
}
return res;
}
};
Matrix qpow(Matrix A, ll b)//矩阵快速幂
{
Matrix res = A, k = A;
b--;
while(b)
{
if(b & 1) res = res * k;
k = k * k;
b >>= 1;
}
return res;
}
class Treap_Max//维护了许多信息的Treap
{
queue<int> trashcan;
struct Node
{
int lson, rson, size, val, cov, key;
int rev_tag, cov_tag;
int sum, lmax, rmax, maxn;
} t[N];
int root, cnt;
int new_node(int k)
{
int x;
if(!trashcan.empty())//先垃圾篓里面找
x = trashcan.front(), trashcan.pop();
else x = ++cnt;
t[x].lson = t[x].rson = t[x].cov = t[x].rev_tag = t[x].cov_tag = 0;
t[x].size = 1;
t[x].val = t[x].sum = t[x].maxn = k;
t[x].lmax = t[x].rmax = max(0, k);
t[x].key = rand();//随机优先级
return x;
}
void push_up(int p)
{
if(!p) return;
t[p].size = t[t[p].lson].size + t[t[p].rson].size + 1;
t[p].sum = t[t[p].lson].sum + t[t[p].rson].sum + t[p].val;
t[p].lmax = max(t[t[p].lson].lmax, t[t[p].lson].sum + t[p].val + t[t[p].rson].lmax, 0);//与0取最大
t[p].rmax = max(t[t[p].rson].rmax, t[t[p].rson].sum + t[p].val + t[t[p].lson].rmax, 0);
t[p].maxn = max(t[p].val, t[p].val + t[t[p].lson].rmax + t[t[p].rson].lmax);
if(t[p].lson) t[p].maxn = max(t[p].maxn, t[t[p].lson].maxn);
if(t[p].rson) t[p].maxn = max(t[p].maxn, t[t[p].rson].maxn);
}
void apply_rev(int p)//对以p为根节点的树反转
{
if(!p) return ;
swap(t[p].lson, t[p].rson);
swap(t[p].lmax, t[p].rmax);
t[p].rev_tag ^= 1;
}
void apply_cov(int p, int c)//对以p为根节点的树覆盖
{
t[p].val = t[p].cov = c;
t[p].sum = t[p].size * c;
t[p].lmax = t[p].rmax = max(0, t[p].sum);
t[p].maxn = max(c, t[p].sum);
t[p].cov_tag = 1;
}
void push_down(int p)//下传标记
{
if(!p) return;
if(t[p].rev_tag)//有标记
{
if(t[p].lson) apply_rev(t[p].lson);
if(t[p].rson) apply_rev(t[p].rson);
t[p].rev_tag = 0;//清空
}
if(t[p].cov_tag)//有标记
{
if(t[p].lson) apply_cov(t[p].lson, t[p].cov);
if(t[p].rson) apply_cov(t[p].rson, t[p].cov);
t[p].cov_tag = t[p].cov = 0;//清空
}
}
void trash(int p)//回收以p为根的子树
{
if(!p) return;
trashcan.push(p);
if(t[p].lson) trash(t[p].lson);//回收左儿子
if(t[p].rson) trash(t[p].rson);//回收右儿子
}
void split_by_rank(int p, int k, int &x, int &y)//以第k为界限分裂
{
if(!p)
{
x = y = 0;
return;
}
push_down(p);
if(t[t[p].lson].size + 1 <= k)//左边装不下
{
x = p;
split_by_rank(t[p].rson, k - t[t[p].lson].size - 1, t[p].rson, y);
}
else
{
y = p;
split_by_rank(t[p].lson, k, x, t[p].lson);
}
push_up(p);
}
int merge(int x, int y)//合并
{
if(!x || !y) return x + y;
if(t[x].key <= t[y].key)
{
push_down(x);
t[x].rson = merge(t[x].rson, y);
push_up(x);
return x;
}
else
{
push_down(y);
t[y].lson = merge(x, t[y].lson);
push_up(y);
return y;
}
}
int a[N];
int build(int l, int r)//构造a数组的平衡树,避免一个一个插入
{
if(l == r) return new_node(a[l]);
int mid = l + r;
mid >>= 1;
return merge(build(l, mid), build(mid + 1, r));
}
void insert()//从pos处插入tot个
{
int pos, tot;
cin >> pos >> tot;
int x, y;
split_by_rank(root, pos, x, y);
for(int i = 1; i <= tot; i++)
cin >> a[i];
x = merge(x, build(1, tot));
root = merge(x, y);
}
void delet()//从pos处删除tot个
{
int pos, tot;
cin >> pos >> tot;
int x, y, z;
split_by_rank(root, pos - 1, x, y);
split_by_rank(y, tot, y, z);
trash(y);
root = merge(x, z);
}
void make_same()//从pos处覆盖tot个为c
{
int pos, tot, c;
cin >> pos >> tot >> c;
int x, y, z;
split_by_rank(root, pos - 1, x, y);
split_by_rank(y, tot, y, z);
apply_cov(y, c);
root = merge(merge(x, y), z);
}
void Reverse()//从pos起翻转tot个
{
int pos, tot;
cin >> pos >> tot;
int x, y, z;
split_by_rank(root, pos - 1, x, y);
split_by_rank(y, tot, y, z);
apply_rev(y);
root = merge(merge(x, y), z);
}
void get_sum()//a到b区间和
{
int a, b;
cin >> a >> b;
int x, y, z;
split_by_rank(root, a - 1, x, y);
split_by_rank(y, b, y, z);
cout << t[y].sum << '\n';
root = merge(merge(x, y), z);
}
void max_sum()//最大子段和
{
cout << t[root].maxn << '\n';
}
};
struct Longest_Common_Subsequence//最长公共子序列
{
int dp[N][N], a[N], b[N];
int f[N], map[N], ans;
Longest_Common_Subsequence(): ans(0) {}
void LCS1()
{
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(a[i] == b[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
ans = dp[n][m];
}
void LCS2()
{
for(int i = 1; i <= n; ++i)
map[a[i]] = i;
for(int i = 1; i <= m; ++i)
f[i] = 0x3f3f3f3f;
int ans = 0;
for(int i = 1; i <= m; ++i)
{
int l = 0, r = ans, mid;
if(map[b[i]] > f[ans])
f[++ans] = map[b[i]];
else
{
while(l < r)
{
mid = (l + r) / 2;
if(f[mid] > map[b[i]])
r = mid;
else l = mid + 1;
}
f[l] = min(map[b[i]], f[l]);
}
}
}
};
struct Longest_Increasing_Subsequence//最长上升子序列
{
Longest_Increasing_Subsequence(): ans(0) {}
int a[N], f[N], ans;
void LIS()
{
for(int i = 1; i <= n; ++i)
{
int j = lower_bound(f + 1, f + n + 1, a[i]) - f - 1;
ans = max(ans, j + 1);
f[j] = a[i];
}
}
};
struct Manacher//马拉车求回文串
{
string s, t;
int ans, p[N];
void manacher()
{
t = "$#";
int n = s.size();
for(int i = 0; i < n; ++i)
{
t += s[i];
t += "#";
}
int mr = 0, mid = 0, m = t.size();
for(int i = 1; i < m; ++i)
{
if(mr > i)
p[i] = min(p[mid * 2 - i], mr - i);
else p[i] = 1;
while(t[i + p[i]] == t[i - p[i]])
++p[i];
if(mr < p[i] + i)
{
mr = p[i] + i;
mid = i;
}
ans = max(ans, p[i]);
}
--ans;
}
};
struct The_Diameter_Of_A_Tree//树的直径
{
Chain_Forward_Star C;
int dis[N];//到u点的距离
int max_dis;
int p;//最远点储存在p
void dfs(int u, int f)//当前点,父亲
{
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v, w = C.e[i].w;
if(v == f) continue;
dis[v] = dis[u] + w;
if(dis[v] > max_dis)
{
max_dis = dis[v];
p = v;
}
dfs(v, u);
}
}
void find_diameter()//x,y是直径,max_dis为直径的长度
{
dfs(1, 0);
int x = p;
max_dis = 0;
dis[p] = 0;
dfs(x, -1);
}
};
struct Divide_And_Conquer_Points//点分治
{
Chain_Forward_Star C;
int sum, root;//子树的大小,子树的重心。
int dis[N];//某个节点到其子树中节点的距离
int ask[1010], ans[1010];
int dp[N], pd[100000010], siz[N];//dp 用于存储子树的最大不平衡度,pd 用于标记某个距离是否被当前子树覆盖,siz 存储子树的大小。
int sta[N], top;
int tmp[N];//临时存储距离值,用于后续处理
int vis[N];
void get_focus(int u, int f)//找到以 u 为根的子树的重心
{
dp[u] = 0, siz[u] = 1;
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v;
if(v == f || vis[v]) continue;
get_focus(v, u);
siz[u] += siz[v];
dp[u] = max(dp[u], siz[v]);
}
dp[u] = max(dp[u], sum - siz[u]);
if(dp[u] < dp[root]) root = u;
}
void get_dis(int u, int f)//递归地计算从 u 到其子树中所有节点的距离,并将这些距离存储在 sta 栈中
{
sta[++top] = dis[u];
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v, w = C.e[i].w;
if(v == f || vis[v]) continue;
dis[v] = dis[u] + w;
get_dis(v, u);
}
}
void calc(int u)//遍历子树并计算距离,检查是否存在满足条件的路径。
{
int c = 0;
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v, w = C.e[i].w;
if(vis[v]) continue;
top = 0, dis[v] = w, get_dis(v, u);
for(int j = top ; j >= 1; --j)
for(int k = 1; k <= m; ++k)
if(ask[k] >= sta[j])
ans[k] |= pd[ask[k] - sta[j]];
for(int j = top ; j >= 1; --j)
tmp[++c] = sta[j], pd[sta[j]] = 1;
}
for(int i = 1; i <= c; i++)
pd[tmp[i]] = 0;
}
void solve(int u)//以 u 为根的子树,遍历所有未访问的子树
{
vis[u] = pd[0] = 1;
calc(u);
for(int i = C.head[u]; ~i; i = C.e[i].nxt)
{
int v = C.e[i].v;
if(vis[v]) continue;
dp[0] = INT_MAX, sum = siz[v], root = 0;
get_focus(v, 0), solve(root);
}
}
void work()
{
cin >> n >> m;
dp[0] = sum = n;
for(int i = 1, u, v, w; i < n; ++i)
{
cin >> u >> v >> w;
C.add_edge(u, v, w);
C.add_edge(v, u, w);
}
for(int i = 1; i <= m; ++i)
cin >> ask[i];
get_focus(1, 0), solve(root);
for(int i = 1; i <= m; ++i)
cout << (ans[i] ? "yes\n" : "no\n");
}
};
struct shuweiDP
{
int a[30];//拆位数组
int b;//b进制
int dp[60][60];//记忆化数组,dp[pos]定义为在没有限制没有前导零的情况,从pos位开始填的答案
//状态数随题目条件改变,一般不止一维,记得初始化为-1
//pos表示还有几位要填
//lim表示是否有最高位限制
//lead表示是否填的数全是前导0,这里0也会被判成前导0,不过一般不影响结果
//st是与题目相关的状态,数量和名字都依据题目变化
int dfs(int pos, int st, int limit, int lead)
{
if(pos == 0) return 1;//递归到底层,满足要求就返回1
if(!limit && !lead && dp[pos][st] != -1)
return dp[pos][st]; //如果发现没有限制,不全是0且状态搜过则直接返回
int up = limit ? a[pos] : b - 1;//当前位最高能填多少
int ret = 0;
for(int i = 0; i <= up; ++i)//一些与题目要求去条件的判断
ret += dfs(pos - 1, st, limit && (i == up), lead && !i);
return (!limit && !lead) ? dp[pos][st] = ret : ret;//如果发现没有限制,不全是0,则加入记忆化数组
}
int calc(int x)
{
if(!x) return 1;//把<=0的特判掉
int len = 0;
while(x) a[++len] = x % b, x /= b;
return dfs(len, 0, 1, 1);
}
};
template<typename T = int>class Monotonic_queue//区间最小值单调队列
{
public:
int k;
struct node
{
int id;
T val;
};
Monotonic_queue(int k_):k(k_) {de.clear();}
node front() {return de.front();}
node back() {return de.back();}
void push_back(int id, int x)
{
while(!de.empty() && x >= de.back().val)
de.pop_back();
de.push_back(node{id, x});
while(id - k >= de.front().id)
de.pop_front();
}
private:
deque<node> de;
};
template<typename T = int>class Sparse_Table//ST表
{
public:
Sparse_Table(int n_ = N - 1)
{
Log2[0] = Log2[1] = 0;
for(int i = 2; i <= n_; ++i)
Log2[i] = Log2[i >> 1] + 1;
}
void build_st(T *a) {Build_st(a);}
T query(int l, int r) {return Query(l, r);}
private:
T st[N][32];//ST[i][j]表示以i为起点,(2^j)-1为长度的区间最大值
int Log2[N];//减小log带来的常数
void Build_st(T *a)
{
for(int i = 1; i <= n; ++i)
st[i][0] = a[i];
for(int i = 1; i <= Log2[n]; ++i)//先枚举区间长度
for(int j = 1; j + ((1 << i) - 1) <= n; ++j)
st[j][i] = max(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
}
T Query(int l, int r)
{
int k = Log2[r - l + 1];
return max(st[l][k], st[r - (1 << k) + 1][k]);
}
};
template<typename T = int>class Segment_Tree//线段树
{
public:
void build_tree(T *a) {Build_tree(1, 1, n, a);}
void modify_add(int x, int y, T v) {Modify(1, 1, n, x, y, v, 1);}
void modify_mul(int x, int y, T v) {Modify(1, 1, n, x, y, v, 2);}
void modify_cov(int x, int y, T v) {Modify(1, 1, n, x, y, v, 3);}
T query(int x, int y) {return Query(1, 1, n, x, y);}
private:
#define mid ((l + r) >> 1)
#define ls (p << 1)
#define rs (p << 1 | 1)
struct node
{
T sum, max_val, min_val, add_tag, mul_tag, cov_tag;
T lmax, rmax, maxn;//最大子段和
node(): sum(0), max_val(-INF), min_val(INF), add_tag(0), mul_tag(1), cov_tag(-INF), lmax(0), rmax(0), maxn(0) {}
} t[N << 2];
void Apply_add(int p, int l, int r, T v)
{
t[p].sum += (r - l + 1) * v;
t[p].add_tag += v;
t[p].max_val += v;
t[p].min_val += v;
}
void Apply_mul(int p, T v)
{
t[p].mul_tag *= v;
t[p].add_tag *= v;
t[p].sum *= v;
t[p].max_val *= v;
t[p].min_val *= v;
}
void Apply_cov(int p, int l, int r, T v)
{
t[p].cov_tag = v;
t[p].sum = (r - l + 1) * v;
t[p].max_val = v;
t[p].min_val = v;
t[p].add_tag = 0;
t[p].mul_tag = 1;
}
void Push_up(int p)
{
t[p].sum = t[ls].sum + t[rs].sum;
t[p].max_val = max(t[ls].max_val, t[rs].max_val);
t[p].min_val = min(t[ls].min_val, t[rs].min_val);
t[p].lmax = max(t[ls].lmax, t[ls].sum + t[rs].lmax);
t[p].rmax = max(t[ls].rmax + t[rs].sum, t[rs].rmax);
t[p].maxn = max(t[ls].maxn, t[rs].maxn, t[ls].rmax + t[rs].lmax);
}
void Push_down(int p, int l, int r)
{
if(t[p].cov_tag != -INF)
{
Apply_cov(ls, l, mid, t[p].cov_tag);
Apply_cov(rs, mid + 1, r, t[p].cov_tag);
t[p].cov_tag = -INF;
}
if(t[p].mul_tag != 1)
{
Apply_mul(ls, t[p].mul_tag);
Apply_mul(rs, t[p].mul_tag);
t[p].mul_tag = 1;
}
if(t[p].add_tag)
{
Apply_add(ls, l, mid, t[p].add_tag);
Apply_add(rs, mid + 1, r, t[p].add_tag);
t[p].add_tag = 0;
}
}
void Build_tree(int p, int l, int r, T *a)//建树
{
if(l == r)
{
t[p].sum = a[l];
t[p].max_val = a[l];
t[p].min_val = a[l];
t[p].lmax = a[l];
t[p].rmax = a[l];
t[p].maxn = a[l];
return;
}
Build_tree(ls, l, mid, a);
Build_tree(rs, mid + 1, r, a);
Push_up(p);
}
void Modify(int p, int l, int r, int x, int y, T v, int flag)//区间加 ,乘 ,覆盖(1,2,3)
{
if(r < x || y < l) return;
if(x <= l && r <= y)
{
if(flag == 1) Apply_add(p, l, r, v);
if(flag == 2) Apply_mul(p, v);
if(flag == 3) Apply_cov(p, l, r, v);
return;
}
Push_down(p, l, r);
if(x <= mid) Modify(ls, l, mid, x, y, v, flag);
if(y > mid) Modify(rs, mid + 1, r, x, y, v, flag);
Push_up(p);
}
T Query(int p, int l, int r, int x, int y)
{
if(r < x || y < l) return 0;
if(x <= l && r <= y) return t[p].sum;
Push_down(p, l, r);
if(y <= mid) return Query(ls, l, mid, x, y);
if(x > mid) return Query(rs, mid + 1, r, x, y);
T res = 0;
if(x <= mid) res += Query(ls, l, mid, x, y);
if(y > mid) res += Query(rs, mid + 1, r, x, y);
return res;
}
#undef mid
#undef ls
#undef rs
};
template<typename T = int>class Dynamic_Segment_Tree//动态开点线段树
{
public:
Dynamic_Segment_Tree() {cnt = root = 1;}
void modify_add(int x, int y, T v) {Modify(root, 1, n, x, y, v, 1);}
void modify_mul(int x, int y, T v) {Modify(root, 1, n, x, y, v, 2);}
void modify_cov(int x, int y, T v) {Modify(root, 1, n, x, y, v, 3);}
T query(int x, int y) {return Query(root, 1, n, x, y);}
private:
#define mid ((l + r) >> 1)
#define ls t[p].lson
#define rs t[p].rson
struct node
{
int lson, rson;
T sum, max_val, min_val, add_tag, mul_tag, cov_tag;
T lmax, rmax, maxn;//最大子段和
node(): sum(0), max_val(-INF), min_val(INF), add_tag(0), mul_tag(1), cov_tag(-INF), lson(0), rson(0), lmax(0), rmax(0), maxn(0) {}
} t[N << 2];
int cnt, root;
int New_node() {return ++cnt;}
void Apply_add(int p, int l, int r, T v)
{
t[p].sum += (r - l + 1) * v;
t[p].add_tag += v;
t[p].max_val += v;
t[p].min_val += v;
}
void Apply_mul(int p, T v)
{
t[p].mul_tag *= v;
t[p].add_tag *= v;
t[p].sum *= v;
t[p].max_val *= v;
t[p].min_val *= v;
}
void Apply_cov(int p, int l, int r, T v)
{
t[p].cov_tag = v;
t[p].sum = (r - l + 1) * v;
t[p].max_val = v;
t[p].min_val = v;
t[p].add_tag = 0;
t[p].mul_tag = 1;
}
void Push_up(int p)
{
t[p].sum = t[ls].sum + t[rs].sum;
t[p].max_val = max(t[ls].max_val, t[rs].max_val);
t[p].min_val = min(t[ls].min_val, t[rs].min_val);
t[p].lmax = max(t[ls].lmax, t[ls].sum + t[rs].lmax);
t[p].rmax = max(t[ls].rmax + t[rs].sum, t[rs].rmax);
t[p].maxn = max(t[ls].maxn, t[rs].maxn, t[ls].rmax + t[rs].lmax);
}
void Push_down(int p, int l, int r)
{
if(!ls) ls = New_node();
if(!rs) rs = New_node();
if(t[p].cov_tag != -INF)
{
Apply_cov(ls, l, mid, t[p].cov_tag);
Apply_cov(rs, mid + 1, r, t[p].cov_tag);
t[p].cov_tag = -INF;
}
if(t[p].mul_tag != 1)
{
Apply_mul(ls, t[p].mul_tag);
Apply_mul(rs, t[p].mul_tag);
t[p].mul_tag = 1;
}
if(t[p].add_tag)
{
Apply_add(ls, l, mid, t[p].add_tag);
Apply_add(rs, mid + 1, r, t[p].add_tag);
t[p].add_tag = 0;
}
}
void Modify(int p, int l, int r, int x, int y, T v, int flag)//区间加,乘,覆盖(1,2,3)
{
if(r < x || y < l) return;
if(x <= l && r <= y)
{
if(flag == 1) Apply_add(p, l, r, v);
if(flag == 2) Apply_mul(p, v);
if(flag == 3) Apply_cov(p, l, r, v);
return;
}
Push_down(p, l, r);
if(x <= mid) Modify(ls, l, mid, x, y, v, flag);
if(y > mid) Modify(rs, mid + 1, r, x, y, v, flag);
Push_up(p);
}
T Query(int p, int l, int r, int x, int y)
{
if(r < x || y < l) return 0;
if(x <= l && r <= y) return t[p].sum;
Push_down(p, l, r);
if(y <= mid) return Query(ls, l, mid, x, y);
if(x > mid) return Query(rs, mid + 1, r, x, y);
T res = 0;
if(x <= mid) res += Query(ls, l, mid, x, y);
if(y > mid) res += Query(rs, mid + 1, r, x, y);
return res;
}
#undef mid
#undef ls
#undef rs
};
template<typename T = int>class Rotate_Treap//旋转Treap
{
//千万别乱用
public:
Rotate_Treap() {Build_treap();}
void insert(T val) {Insert(root, val);}
void remove(T val) {Remove(root, val);}
int get_rank(T val) {return Get_rank(root, val);}
T get_val(int k) {return Get_val(root, k);}
T get_pre(T val) {return Get_pre(val);}
T get_next(T val) {return Get_next(val);}
private:
#define ls(p) t[p].lson
#define rs(p) t[p].rson
int root, cnt;
struct node
{
int lson, rson;//左右儿子
T val, key;//值,优先级(随机)
int tot, size;//值的个数,子树大小
node(): lson(0), rson(0), val(0), key(0), tot(0), size(0) {}
} t[N];
int New_node(T val)//创建值为val的新节点
{
t[++cnt].val = val;
t[cnt].key = rand();//优先级随机
t[cnt].tot = t[cnt].size = 1;
return cnt;//返回节点编号
}
void Push_up(int p)//更新节点子树大小
{
t[p].size = t[ls(p)].size + t[ls(p)].size + t[p].tot;//节点子树的大小=左子树+右子树+当前节点值的个数
}
void Build_treap()//建树堆
{
New_node(-INF);
New_node(INF);
root = 1, rs(root) = 2;
Push_up(root);
}
void Rotate_r(int &p)//右旋
{
int q = ls(p);
ls(p) = rs(q);
rs(q) = p;
p = q;
Push_up(rs(q));
Push_up(p);
}
void Rotate_l(int &p)//左旋
{
int q = rs(p);
rs(p) = ls(q);
ls(q) = p;
p = q;
Push_up(ls(p));
Push_up(p);
}
void Insert(int &p, T val)//插入值为val的新节点
{
if(!p)//子树为空,新建
{
p = New_node(val);
return;
}
if(val == t[p].val)//如果值和当前节点相同
{
t[p].tot++;//个数加1就好
Push_up(p);//更新当前子树大小
return;
}
if(val < t[p].val)
{
Insert(ls(p), val);//要插到左边
if(t[p].key < t[ls(p)].key)//如果优先级不满足
Rotate_r(p); //右旋
}
else
{
Insert(rs(p), val);//要插到右边
if(t[p].key < t[rs(p)].key)//如果优先级不满足
Rotate_l(p); //左旋
}
Push_up(p);//更新节点子树大小
}
void Remove(int &p, T val)//删除1个值为val的节点
{
if(!p) return;//如果为空直接返回
if(val == t[p].val)//找到值为val的节点
{
if(t[p].tot > 1)//如果个数超过一个
{
--t[p].tot;//直接把个数减1
Push_up(p);//更新当前节点的子树大小
return;
}
if(ls(p) || rs(p))//如果存在子树
{
if(rs(p) == 0 || t[ls(p)].key > t[rs(p)].key)
Rotate_r(p), Remove(rs(p), val); //右旋
else Rotate_l(p), Remove(ls(p), val);//左旋
Push_up(p);//更新子树大小
}
else p = 0;//到叶子节点
return;
}
val <= t[p].val ? Remove(ls(p), val) : Remove(rs(p), val);//递归查找要删除的数的位置
Push_up(p);//更新当前节点子树大小
}
int Get_rank(int p, T val)//询问排名
{
if(!p) return 0;//如果节点为空返回0
if(val == t[p].val)
return t[ls(p)].size + 1; //左儿子都比他小
if(val < t[p].val)
return Get_rank(ls(p), val); //去左子树里面查找
return Get_rank(rs(p), val) + t[ls(p)].size + t[p].tot;//同时左子树个数+当前节点个数比他小
}
T Get_val(int p, int k)//询问排名第k
{
if(!p) return INF;//如果节点为空返回INF
if(t[ls(p)].size >= k)
return Get_val(ls(p), k); //继续向左查找
if(t[ls(p)].size + t[p].tot >= k)
return t[p].val; //当前节点就是第k大的数
return Get_val(rs(p), k - t[ls(p)].size - t[p].tot);//在右子树里找剩下的
}
T Get_pre(T val)//询问前驱
{
T res = -INF;
int p = root;
while(p)
{
if(val >= t[p].val)
{
res = t[p].val;
p = rs(p);
}
else p = ls(p);
}
return res;
}
T Get_next(T val)//询问后继
{
T res = INF;
int p = root;
while(p)
{
if(val <= t[p].val)
{
res = t[p].val;
p = ls(p);
}
else p = rs(p);
}
return res;
}
};
template<typename T = int>class FHQ_Treap//范浩强无旋Treap
{
public:
FHQ_Treap() {Build_treap();}
void insert(T val) {Insert(val);}
void remove(T val) {Remove(val);}
int get_rank(T val) {return Get_rank(val);}
T get_val(int k) {return Get_val(root, k);}
T get_pre(T val) {return Get_pre(val);}
T get_next(T val) {return Get_next(val);}
private:
int root, cnt;
struct node
{
int lson, rson;//左右儿子
T val, key;//值,优先级(随机)
int size;//子树大小
node(): lson(0), rson(0), val(0), key(0), size(0) {}
} t[N];
int New_node(T val)//创建值为val的新节点
{
int x = ++cnt;
ls(x) = rs(x) = 0;
t[x].size = 1;
t[x].val = val;
t[x].key = rand();//随机优先级
return x;//返回节点编号
}
void Build_treap()
{
New_node(INF);
New_node(-INF);
root = 1, rs(root) = 2;
Push_up(root);
}
void Push_up(int p)//更新节点子树大小
{
if(!p) return;
t[p].size = t[ls(p)].size + t[rs(p)].size + 1;
}
void Split_by_val(int p, T k, int &x, int &y)//将p子树以按k拆成x和y子树,其中x中的点<=k,y中全部大于k
{
if(!p)
{
x = y = 0;//分裂到头了
return;
}
if(t[p].val <= k)//当前节点小,放x上
{
x = p;//x上暂时放的p子树,还要去看p的右子树
Split_by_val(rs(p), k, rs(p), y);//去看p右子树,如果有<key的则应该保留在p右子树上(最后给x),否则放在y上
}
else
{
y = p;
Split_by_val(ls(p), k, x, ls(p));//去看p左子树,如果有>=key的则应该放在p左子树上(最后给y),否则放在x上
}
Push_up(p);//防止更新0点
}
int Merge(int x, int y)//合并x,y子树,其中x子树的值<=y子树的值,返回根节点
{
if(!x || !y) return x | y;//x如果有一个子树为空则返回另一个子树
if(t[x].key > t[y].key)//x在堆中是在y的上方,而值小于y,故在y的左上方
{
rs(x) = Merge(rs(x), y);//让x的右子树和y合并
Push_up(x);
return x;
}
else//x在y的左下方
{
ls(y) = Merge(x, ls(y));//x和y的左子树合并
Push_up(y);
return y;
}
}
void Insert(T val)//插入值为val的节点
{
int x, y;
Split_by_val(root, val, x, y);
root = Merge(Merge(x, New_node(val)), y);
}
void Remove(T val)//删除值为val的节点
{
int x, y, z;
Split_by_val(root, val, x, z);//把root为根节点的树分为AB两棵树,<=val的A树树根为x,B树树根z
Split_by_val(x, val - 1, x, y);//把x为根节点的树分为CD两棵树,<=val-1的C树树根为x,D树树根y,x<=val,再分x <= val- 1,y就是=val的树
y = Merge(ls(y), rs(y));//直接让y树的左右儿子进行合并,忽略y节点,删除y点
root = Merge(Merge(x, y), z);//先把CD合并,再与原来的B树进行合并
}
int Get_rank(T val)//按值查排名
{
int x, y;
Split_by_val(root, val - 1, x, y);//按val-1分割,x子树大小+1就是排名
val = t[x].size + 1;//储存x的大小+1
root = Merge(x, y);//重新把x,y子树合并,还原root
return val;
}
T Get_val(int p, int k)//按排名查值
{
int tmp = t[ls(p)].size + 1;//当前节点排名tmp=他的左子树节点个数+1
if(tmp == k)
return t[p].val; //刚好等于k,即为找到了
if(tmp > k)
return Get_val(ls(p), k); //说明应该在左子树里继续寻找
return Get_val(rs(p), k - tmp);//说明已经找到tmp个比他小的,再继续找k-tmp
}
T Get_pre(T val)//查询前驱
{
int x, y;
T res;
Split_by_val(root, val - 1, x, y);
res = Get_val(x, t[x].size);//然后找A树内的最大值(即在A树内查询排名为 size 的数值)
root = Merge(x, y);
return res;
}
T Get_next(T val)//查询后继
{
int x, y;
T res;
Split_by_val(root, val, x, y);
res = Get_val(y, 1);//然后找B树内的最小值即在B树内查询排名为1的数值
root = Merge(x, y);
return res;
}
};
//优化,精简,改进,模板化,改写为class
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
system("taskkill /f /t /im studentmain.exe");
return 0;
}