第k小数
#include
using namespace std;
#define ll long long
const int maxn = 5e6 + 10;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int q[maxn];
int quick_sort(int q[], int l, int r, int k)
{
if (l >= r)
return q[l];
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j)
{
do
i++;
while (q[i] < x);
do
j--;
while (q[j] > x);
if (i < j)
swap(q[i], q[j]);
}
if (j - l + 1 >= k)
return quick_sort(q, l, j, k);
else
return quick_sort(q, j + 1, r, k - (j - l + 1));
}
int main()
{
int n, k;
int t;
cin >> t;
while (t--)
{
//scanf("%d%d", &n, &k);
n=read();
k=read();
for (int i = 0; i < n; i++)
q[i]=read();
cout << quick_sort(q, 0, n - 1, k) << endl;
}
}
三分
int three_fen(int l,int r)
{
while(l
数组模拟双向链表
#include
using namespace std;
typedef long long ll;
const int N=10000015,mod=1e9+7;
template
void Debug(T x,string s){
cout<
// #define x first
// #define y second
#define PB push_back
int vis[N],vis_p[N];//value值在链表中的位置,value值对应的数组下标
struct linklist
{
int head=1,tail=1,sz=0,mid=tail;
void insertl(int tot){sz++;
if(sz==1){
head=tail=tot;vis_p[tot]=0;
a[tot].last=-1;a[tot].next=-1;
mid=tail;
}
else{
a[tot].next=head;
a[tot].last=-1;
a[head].last=tot;
vis_p[tot]=vis_p[head]-1;
head=tot;
if(sz%2==1){
movel();
}
else{
mid=mid;
}
}
}
void insertr(int tot){
sz++;
if(sz==1){
head=tail=tot;vis_p[tot]=0;
a[tot].last=-1;a[tot].next=-1;
mid=tot;
}
else{
a[tot].last=tail;
a[tot].next=-1;
a[tail].next=tot;
vis_p[tot]=vis_p[tail]+1;
tail=tot;
if(sz%2==0){
mover();
}
else mid=mid;
}
}
void del(int tot){
int tl=a[tot].last,tr=a[tot].next;
if(tr!=-1)
a[tl].next=tr;
if(tl!=-1)
a[tr].last=tl;
if(tot==head){
head=a[head].next;
}
if(tot==tail){
tail=a[tail].last;
}
if(vis_p[mid]>vis_p[tot]){
if(sz%2==1) mover();
else mid=mid;
}
else if(vis_p[mid]
快读
template
inline _Tp read(_Tp &x) {
char ch = getchar(), sgn = 0; x = 0;
while (ch ^ '-' && !isdigit(ch)) ch = getchar();
if (ch == '-') ch = getchar(), sgn = 1;
while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
if (sgn) x = -x;
return x;
}
int main() {
b = read(a);
}
//可读int, long long short
计算程序运行时间
cerr << "Time execute: " << clock() / (double)CLOCKS_PER_SEC << " sec" << endl;
STL离散化
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
数学
gcd
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
扩展欧几里得
#include
#include
#include
using namespace std;
int exgcd(int a,int b,int &x,int &y)//扩展欧几里得算法
{
if(b==0)
{
x=1;y=0;
return a; //到达递归边界开始向上一层返回
}
int r=exgcd(b,a%b,x,y);
int temp=y; //把x y变成上一层的
y=x-(a/b)*y;
x=temp;
return r; //得到a b的最大公因数
}
容斥原理
#include
using namespace std;
typedef long long ll;
const int Maxn = 20;
int Number[Maxn + 5];
ll N, M, Tot;
ll Ans = 0;
bool is_prime(int x)
{
for(int i=2;i*i<=x;i++){
if(x%i==0) return false;
}
return true;
}
ll Gcd(ll A, ll B){
return !B ? A : Gcd(B, A % B);
}
void Dfs(ll Cur, ll Cnt, ll Limit, ll LCM){
if (Cnt == Limit) {
if (Limit & 1) {
Ans += (N - 1) / LCM;
}
else {
Ans -= (N - 1) / LCM;
}
return;
}
if (Cur >= Tot) {
return ;
}
ll NowLCM = LCM == -1 ? Number[Cur] : LCM;
Dfs(Cur + 1, Cnt + 1, Limit, Number[Cur] / Gcd(NowLCM, Number[Cur]) * NowLCM);
Dfs(Cur + 1, Cnt, Limit, LCM);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.txt","r",stdin);
freopen("aout.txt","w",stdout);
#endif
int tot=0;
// Number[]=2;
for(int i=2;i<=100;i++){
if(is_prime(i)){
Number[++tot]=i;
}
if(tot>17) break;
}
int t;cin>>t;
while (t--) {
cin>>N>>M;
Tot = 1;
Ans = 0;
Tot=M+1;
for (int i = 1; i < Tot; i++) {
Dfs(1, 0, i, -1);
}
printf("%lldn", N-Ans-1);
}
}
卡特兰数
#include
#include
#define N 60
using namespace std;
int main()
{
int h[101][2*N+1],i,j,k,l,n;
memset(h,0,sizeof(h));
h[0][1]=1;h[1][1]=1;
for(i=2;i<=100;i++)
{
for(j=0;j0;j--)
printf("%d",h[n][j]);
printf("n");
}
return 0;
}
组合数
#include
#include
#define ll long long
using namespace std;
const ll maxn=2*150007;
const ll mod=998244353;
ll quick_mod(ll a, ll b)
{
ll ans = 1;
a %= mod;
while(b)
{
if(b & 1)
{
ans = ans * a % mod;
b--;
}
b >>= 1;
a = a * a % mod;
}
return ans;
}
ll C(ll n, ll m)
{
if(m > n) return 0;
ll ans = 1;
for(int i=1; i<=m; i++)
{
ll a = (n + i - m) % mod;
ll b = i % mod;
ans = ans * (a * quick_mod(b, mod-2) % mod) % mod;
}
return ans;
}
ll Lucas(ll n, ll m)
{
if(m == 0) return 1;
return C(n % mod, m % mod) * Lucas(n / mod, m / mod) % mod;
}
//递推公式
const int N = 1e6 + 7, mod = 1e9 + 7;
int n, m, k, t;
int inv[N];
int fact[N], infact[N];
void init (int n)
{
fact[0] = infact[0] = inv[0] = inv[1] = 1;
for (int i = 2; i <= n; ++ i)
inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
for (int i = 1; i <= n; ++ i) {
fact[i] = 1ll * fact[i - 1] * i % mod;
infact[i] = 1ll * infact[i - 1] * inv[i] % mod;
}
}
int C(int n, int m)
{
if(n < m) return 0;
if(m == 0 || n == m) return 1;
return 1ll * fact[n] * infact[m] % mod * infact[n - m] % mod;
}
中国剩余定理
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
//扩展欧几里得,ax+by=gcd(a,b)
ll e_gcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1,y=0;
return a;
}
ll res=e_gcd(b,a%b,y,x);
y-=(a/b)*x;
return res;
}
//中国剩余定理,pri[]存放互质的数,r[]存放余数,n为个数
ll china(ll pri[],ll r[],ll n){
ll M=1,m,d,res=0;
for(int i=0;i
素数筛
#include
using namespace std;
const int maxn=1e6;//这个是在哪一个范围内
int prime[maxn];
int visit[maxn];//1代表是偶数,0代表是奇数
void Prime()
{
memset(visit,0,sizeof(visit));
memset(prime,0,sizeof(visit));
visit[1]=1;
for (int i = 2;i <= maxn; i++)
{
if (!visit[i])
{
prime[++prime[0]] = i;
}
for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++)
{
visit[i*prime[j]] = 1;
if (i % prime[j] == 0)
{
break;
}
}
}
}
for(int i=2;i<=10000000;i++)
{
if(!f[i])prm[++cnt]=i,num[i]=1;
for(int j=1;j<=cnt && i*prm[j]<=10000000;j++)
{
f[i*prm[j]]=true;
num[i*prm[j]]=num[i]+1;
if(i%prm[j]==0)break;
}
}
void euler()
{
for (int i = 1; i
#include
using namespace std;
typedef long long ll;
ll read(string s,ll mod){
ll x=0;
for(int i=0;i>=1;
}
return sum;
}
ll phi(ll x){
ll t=x;
for(int i=2;i<=x/i;i++)
if(x%i==0){
while(x%i==0)x/=i;
t=t*(i-1)/i;
}
if(x>1)t=t*(x-1)/x;
return t;
}
int main(){
ll x,mod,n;
string nn;
cin>>x>>nn>>mod;
if(x==0){
if(nn=="1")cout<<1%mod;
else cout<<"0";
return 0;
}
x%=mod;
n=read(nn,phi(mod));
cout<
逆元
void init(){
fac[0] = 1;
for(int i=1;i<=MN;i++)
fac[i] = (ll)fac[i-1]*i%mod;
inv[MN] = qpow(fac[MN],mod-2);
for(int i=MN-1;i>=0;i--)
inv[i] = (ll)inv[i+1]*(i+1)%mod;
}
int C(int n,int m){
if(m>n) return 0;
return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll pow_mod(ll a, ll b, ll p){//a的b次方求余p
ll ret = 1;
while(b){
if(b & 1) ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
ll Fermat(ll a, ll p){//费马求a关于b的逆元
return pow_mod(a, p-2, p);
}
质因数分解
bool vis[N];
ll prime[N];
int cnt=0;
void primes()
{
for(int i=2;i<=N;i++){
if(vis[i]) {
continue;
}
prime[++cnt]=i;
for(int j=1;j<=N/i;j++){
vis[i*j]=1;
}
}
}
ll getprimefactor(long long n)
{
ll ans=0;
if(n==1){
return 0;
}
if(!vis[N]){
return 1;
}
for(int i=1;i<=cnt&&prime[i]*prime[i]<=n;i++){
while(n%prime[i]==0){
ans++;
n/=prime[i];
}
}
if(n>1){
return ans+1;
}
return ans;
}
数据结构
ST表
void ST_init()
{
for(int i=1;i<=N;++i)
ST[i][0]=a[i];
for(int j=1;j<30;++j)
{
for(int i=1;i<=N;++i)
{
if(i+(1<N) break;
ST[i][j]=__gcd(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
}
}
}
long long ST_query(int s,int e)
{
int k=(int)((log(e-s+1.0)/log(2.0)));
return __gcd(ST[s][k],ST[e-(1<
优先队列
#include
#include
using namespace std;
int main()
{
int n;
while(cin>>n)
{
int i,k,j,t1;
long long sum=0;
priority_queue,greater > p;
for(i=0;i>k;
p.push(k);
}
while(p.size()!=1)
{
t1=p.top();
p.pop();
t1+=p.top();
sum+=t1;
p.pop();
p.push(t1);
}
cout<
树状数组
//树状数组模板
int sum[N];
int lowbit(int x)
{
return x & (-x);
}
void add(int x, int num)
{
while (x <= n)
{
sum[x] += num;
x += lowbit(x);
}
}
int ask(int x)
{
int res = 0;
while (x > 0)
{
res += sum[x];
x -= lowbit(x);
}
return res;
}
单调栈
int tot=0;
h[m+1]=0;
for(int j=1;j<=m+1;j++){
while(tot&&h[que[tot]]>h[j]){
ans=max(ans,(j-1-que[tot-1])[que[tot]]);
//这里可以理解为以 h[que[tot]]个高度可以向左向右拓展的面积。
tot--;
}
que[++tot]=j;
}
线段树
#include
#include
#include
using namespace std;
const int N = 100005;
const int INF = 0x3f3f3f3f;
int s[N << 2] ,lc[N << 2] ,rc[N << 2];
int n,m,num[N];
void build(int u ,int l ,int r) {
lc[u] = l;
rc[u] = r;
if(l == r) {
s[u] = num[l];
return ;
}
int mid = (l + r) / 2;
build(u * 2 , l , mid);
build(u * 2 + 1 , mid + 1 ,r);
s[u] = min(s[u * 2] , s[u * 2 + 1]);
}
void change(int u , int x , int v) {
if(lc[u] == x && rc[u] == x) {
s[u] = v;
return ;
}
int mid = (lc[u] + rc[u]) / 2;
if(x <= mid)
change(u * 2 , x , v);
else
change(u * 2 + 1 , x , v);
s[u] = min(s[u * 2] , s[u * 2 + 1]);
}
int query(int u , int l ,int r) {
int res = INF;
if(l <= lc[u] && r >= rc[u]) {
return s[u];
}
int mid = (lc[u] + rc[u]) / 2;
if(l <= mid)
res = min(res , query(u * 2 , l , r));
if(r > mid)
res = min(res , query(u * 2 + 1 , l , r));
return res;
}
#include
using namespace std;
typedef long long ll;
#define lowbit(x) ((x)&(-x))
const ll mod = 998244353;
ll powmod(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;
}
const int N = 1e5+50;
int n,m;
struct node
{
int l,r;
ll x,sum;
int lazy;int flag;
}tree[N<<2];
void push_up(int p)
{
tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%mod;
tree[p].flag=(tree[p<<1].flag&tree[p<<1|1].flag);
}
void push_down(int p)
{
if(tree[p].lazy==0) return;
tree[p<<1].lazy+=tree[p].lazy;
tree[p<<1|1].lazy+=tree[p].lazy;
tree[p<<1].sum=(tree[p<<1].sum*powmod(2,tree[p].lazy))%mod;
tree[p<<1|1].sum=(tree[p<<1|1].sum*powmod(2,tree[p].lazy))%mod;
tree[p].lazy=0;
}
void build_tree(int l,int r,int p)
{
tree[p].l=l,tree[p].r=r;
tree[p].lazy=tree[p].flag=0;
if(l==r){
scanf("%lld",&tree[p].x);
tree[p].sum=tree[p].x;
if(lowbit(tree[p].x)==tree[p].x)
tree[p].flag=1;
return;
}
int mid=l+r>>1;
build_tree(l,mid,p<<1);
build_tree(mid+1,r,p<<1|1);
push_up(p);
}
void update_tree(int l,int r,int p)
{
if(l<=tree[p].l&&tree[p].r<=r&&tree[p].flag){
tree[p].sum=(tree[p].sum*2)%mod;
tree[p].lazy++;
return;
}
if(tree[p].l==tree[p].r){
tree[p].x=tree[p].sum=tree[p].sum+lowbit(tree[p].sum);
if(lowbit(tree[p].x)==tree[p].x){
tree[p].flag=1;
}
return;
}
push_down(p);
int mid=(tree[p].l+tree[p].r)>>1;
if(l<=mid) update_tree(l,r,p<<1);
if(mid>1;
if(l<=mid) {
res=(res+ask_sum(l,r,p<<1))%mod;
}
if(mid
#include
using namespace std;
const int maxn=100010;
int a[maxn+2];
struct tree{
int l,r;
long long pre,add;
}t[4*maxn+2];
void bulid(int p,int l,int r){
t[p].l=l;t[p].r=r;
if(l==r){
t[p].pre=a[l];
return;
}
int mid=l+r>>1;
bulid(p*2,l,mid);
bulid(p*2+1,mid+1,r);
t[p].pre=t[p*2].pre+t[p*2+1].pre;
}
void spread(int p){
if(t[p].add){
t[p*2].pre+=t[p].add*(t[p*2].r-t[p*2].l+1);
t[p*2+1].pre+=t[p].add*(t[p*2+1].r-t[p*2+1].l+1);
t[p*2].add+=t[p].add;
t[p*2+1].add+=t[p].add;
t[p].add=0;
}
}
void change(int p,int x,int y,int z){
if(x<=t[p].l && y>=t[p].r){
t[p].pre+=(long long)z*(t[p].r-t[p].l+1);
t[p].add+=z;
return;
}
spread(p);
int mid=t[p].l+t[p].r>>1;
if(x<=mid) change(p*2,x,y,z);
if(y>mid) change(p*2+1,x,y,z);
t[p].pre=t[p*2].pre+t[p*2+1].pre;
}
long long ask(int p,int x,int y){
if(x<=t[p].l && y>=t[p].r) return t[p].pre;
spread(p);
int mid=t[p].l+t[p].r>>1;
long long ans=0;
if(x<=mid) ans+=ask(p*2,x,y);
if(y>mid) ans+=ask(p*2+1,x,y);
return ans;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
bulid(1,1,n);
for(int i=1;i<=m;i++)
{
int q,x,y,z;
scanf("%d",&q);
if(q==1){
scanf("%d%d%d",&x,&y,&z);
change(1,x,y,z);
}
else {
scanf("%d%d",&x,&y);
cout<
//问最小值
//Q a b 询问(a,b)中最小值
//C a b 将a点值改为b
#include
using namespace std;
#define maxn 200005
int min(int a, int b)
{
return a>b ? b : a;
}
int tree[4 * maxn];
void pushup(int i)
{
tree[i] = min(tree[i << 1], tree[i << 1 | 1]);
}
void build(int i, int l, int r)
{
if (l == r)
{
scanf("%lld", &tree[i]);
return;
}
int mid = (l + r) / 2;
build(i << 1, l, mid);
build(i << 1 | 1, mid + 1, r);
pushup(i);
}
void update(int i, int l, int r, int x, int val)
{
if (l == r)///l==x??±???
{
tree[i] = val;
return;
}
int mid = (l + r) / 2;
if (x <= mid) update(i << 1, l, mid, x, val);
else update(i << 1 | 1, mid + 1, r, x, val);
pushup(i);
}
int query(int i, int l, int r, int x, int y)
{
if (x <= l && r <= y)
return tree[i];
int minn = 9999999;
int mid = (l + r) / 2;
if (x <= mid) minn = min(minn, query(i << 1, l, mid, x, y));
if (y>mid) minn = min(minn, query(i << 1 | 1, mid + 1, r, x, y));
return minn;
}
int main()
{
int n, m;
int b, c;
char a;
while (scanf("%d%d", &n, &m) != -1)
{
build(1, 1, n);
while (m--)
{
scanf(" %c%d%d", &a, &b, &c);
if (a == 'Q')
printf("%dn", query(1, 1, n, b, c));
else
update(1, 1, n, b, c);
}
}
return 0;
}
#include
using namespace std;
#define maxn 200005
int tree[4 * maxn];
void pushup(int i)
{
tree[i] = max(tree[i << 1], tree[i << 1 | 1]);
}
void build(int i, int l, int r)
{
if (l == r)
{
tree[i] = 0;
return;
}
int mid = (l + r) / 2;
build(i << 1, l, mid);
build(i << 1 | 1, mid + 1, r);
pushup(i);
}
void update(int i, int l, int r, int x, int val)
{
if (l == r)
{
tree[i] = val;
return;
}
int mid = (l + r) / 2;
if (x <= mid) update(i << 1, l, mid, x, val);
else update(i << 1 | 1, mid + 1, r, x, val);
pushup(i);
}
int query(int i, int l, int r, int x, int y)
{
if (x <= l && r <= y)
return tree[i];
int maxm = 0;
int mid = (l + r) / 2;
if (x <= mid) maxm = max(maxm, query(i << 1, l, mid, x, y));
if (y>mid) maxm = max(maxm, query(i << 1 | 1, mid + 1, r, x, y));
return maxm;
}
int main()
{
int n, m;
int b, c;
char a;
while (~scanf("%d%d", &n, &m))
{
build(1, 1, n);
while (m--)
{
scanf(" %c%d%d", &a, &b, &c);
if (a == 'Q')
printf("%dn", query(1, 1, n, b, c));
else
update(1, 1, n, b, c);
}
}
}
主席树
#include
#include
#include
using namespace std;
const int maxn = 1e5; // 数据范围
int tot, n, m;
int sum[(maxn << 5) + 10], rt[maxn + 10], ls[(maxn << 5) + 10],
rs[(maxn << 5) + 10];
int a[maxn + 10], ind[maxn + 10], len;
inline int getid(const int &val) { // 离散化
return lower_bound(ind + 1, ind + len + 1, val) - ind;
}
int build(int l, int r) { // 建树
int root = ++tot;
if (l == r) return root;
int mid = l + r >> 1;
ls[root] = build(l, mid);
rs[root] = build(mid + 1, r);
return root; // 返回该子树的根节点
}
int update(int k, int l, int r, int root) { // 插入操作
int dir = ++tot;
ls[dir] = ls[root], rs[dir] = rs[root], sum[dir] = sum[root] + 1;
if (l == r) return dir;
int mid = l + r >> 1;
if (k <= mid)
ls[dir] = update(k, l, mid, ls[dir]);
else
rs[dir] = update(k, mid + 1, r, rs[dir]);
return dir;
}
int query(int u, int v, int l, int r, int k) { // 查询操作
int mid = l + r >> 1,
x = sum[ls[v]] - sum[ls[u]]; // 通过区间减法得到左儿子的信息
if (l == r) return l;
if (k <= x) // 说明在左儿子中
return query(ls[u], ls[v], l, mid, k);
else // 说明在右儿子中
return query(rs[u], rs[v], mid + 1, r, k - x);
}
inline void init() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%d", a + i);
memcpy(ind, a, sizeof ind);
sort(ind + 1, ind + n + 1);
len = unique(ind + 1, ind + n + 1) - ind - 1;
rt[0] = build(1, len);
for (int i = 1; i <= n; ++i) rt[i] = update(getid(a[i]), 1, len, rt[i - 1]);
}
int l, r, k;
inline void work() {
while (m--) {
scanf("%d%d%d", &l, &r, &k);
printf("%dn", ind[query(rt[l - 1], rt[r], 1, len, k)]); // 回答询问
}
}
int main() {
init();
work();
return 0;
}
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 7;
int root[MAXN],n,q,size,num;//size 内存池的大小
ll a[MAXN],s[MAXN],b[MAXN];
struct HJT_tree{
int l,r,cnt;//cnt记录出现次数 sum记录和 val记录节点的值
ll sum,val;
}tree[MAXN*40];
void build(int &now,int l,int r){
now = ++size;
tree[now].cnt = tree[now].sum = tree[now].val = 0;
if(l == r) return ;
int mid = (l+r)>>1;
build(tree[now].l,l,mid);
build(tree[now].r,mid+1,r);
}
void modify(int &now,int pre,int l,int r,int p,int val){
tree[now = ++size] = tree[pre];
tree[now].cnt++,tree[now].sum += val;
if(l == r){
tree[now].val = val;
return ;
}
int mid = (l+r)>>1;
if(p <= mid) modify(tree[now].l,tree[pre].l,l,mid,p,val);
else modify(tree[now].r,tree[pre].r,mid+1,r,p,val);
}
//查前k大值,因为节点存的是值 所以找大的 应该先往右边找 看右边(也就是大的)的数量符合情况嘛
ll query(int now,int pre,int l,int r,int k){
if(l == r) return tree[now].val * k;//因为一个值可能出现多次 那么计算答案的时候要把他们都算上
int mid = (l+r)>>1;
int tmp = tree[tree[now].r].cnt - tree[tree[pre].r].cnt;
if(tmp >= k) return query(tree[now].r,tree[pre].r,mid+1,r,k);
else return query(tree[now].l,tree[pre].l,l,mid,k-tmp) +
tree[tree[now].r].sum - tree[tree[pre].r].sum;//注意左边的k要变成k-tmp的形式
}
int getid(ll x){ return lower_bound(b+1,b+1+num,x)-b; }
int main(){
int T;
scanf("%d",&T);
while(T--){
memset(root,0,sizeof(root));
size = 0;
scanf("%d",&n);
for(int i = 1;i <= n;i ++){
scanf("%lld",&a[i]);
b[i] = a[i];
s[i] = s[i-1] + (1ll*i*i);//这里i会爆 所以开ll
}
sort(b+1,b+1+n);
num = unique(b+1,b+1+n)-b-1;
build(root[0],1,num);
for(int i = 1;i <= n;i ++){
int p = getid(a[i]);
modify(root[i],root[i-1],1,num,p,a[i]);
}
scanf("%d",&q);
int l,r,k;
while(q--){
scanf("%d%d%d",&l,&r,&k);
ll ans = query(root[r],root[l-1],1,num,k);
ans += s[r-l+1];
printf("%lldn",ans);
}
}
return 0;
}
树上倍增求LCA
#include
#include
#include
using namespace std;
const int MAXN=1000010;
inline void read(int &n)
{
char c=getchar();bool flag=0;n=0;
while(c<'0'||c>'9') c=='-'?flag=1,c=getchar():c=getchar();
while(c>='0'&&c<='9') n=n*10+c-48,c=getchar();flag==1?n=-n:n=n;
}
struct node
{
int v,nxt;
}edge[MAXN];
int head[MAXN];
int num=1;
inline void add_edge(int x,int y)
{
edge[num].v=y;
edge[num].nxt=head[x];
head[x]=num++;
}
int f[MAXN][21];
int deep[MAXN];
int n,m,root;
void dfs(int now)
{
for(int i=head[now];i!=-1;i=edge[i].nxt)
if(!deep[edge[i].v])
deep[edge[i].v]=deep[now]+1,f[edge[i].v][0]=now,dfs(edge[i].v);
}
void PRE()
{
for(int i=1;i<=19;i++)
for(int j=1;j<=n;j++)
f[j][i]=f[f[j][i-1]][i-1];
}
int LCA(int x,int y)
{
if(deep[x]=0;i--)
if(deep[f[x][i]]>=deep[y])
x=f[x][i];
if(x==y) return x;
for(int i=19;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int main()
{
memset(head,-1,sizeof(head));
read(n);read(m);read(root);
for(int i=1;i<=n-1;i++)
{
int x,y;read(x);read(y);
add_edge(x,y);
add_edge(y,x);
}
deep[root]=1;
dfs(root);
PRE();
for(int i=1;i<=m;i++)
{
int x,y;
read(x);read(y);
printf("%dn",LCA(x,y));
}
return 0;
}
树链剖分
void dfs1(int o) {
son[o] = -1;
siz[o] = 1;
for (int j = h[o]; j; j = nxt[j])
if (!dep[p[j]]) {
dep[p[j]] = dep[o] + 1;
fa[p[j]] = o;
dfs1(p[j]);
siz[o] += siz[p[j]];
if (son[o] == -1 || siz[p[j]] > siz[son[o]]) son[o] = p[j];
}
}
void dfs2(int o, int t) {
top[o] = t;
cnt++;
dfn[o] = cnt;
rnk[cnt] = o;
if (son[o] == -1) return;
dfs2(son[o], t); // 优先对重儿子进行 DFS,可以保证同一条重链上的点 DFS 序连续
for (int j = h[o]; j; j = nxt[j])
if (p[j] != son[o] && p[j] != fa[o]) dfs2(p[j], p[j]);
}
莫队
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 100010;
int n,m,blo;
int l=1,r=0;
int c[maxn],cnt[maxn],pos[maxn];
ll res=0;
struct Q{
int l,r,id;
}q[maxn];
struct Ans{
ll a,b;
}ans[maxn];
bool cmp(Q a,Q b){
if(pos[a.l]==pos[b.l]) return a.r'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
int main(){
n=read(),m=read();
blo=sqrt(n);
for(int i=1;i<=n;i++) c[i]=read(),pos[i]=(i-1)/blo+1;
for(int i=1;i<=m;i++){
q[i].l=read(),q[i].r=read();
q[i].id=i;
}
sort(q+1,q+1+m,cmp);
for(int i=1;i<=m;i++){
while(lq[i].l){ add(l-1); l--; }
while(rq[i].r){ del(r); r--; }
if(q[i].l==q[i].r){
ans[q[i].id]=(Ans){0,1};
continue;
}
ans[q[i].id]=(Ans){res-(r-l+1),1ll*(r-l+1)*(r-l)};
}
for(int i=1;i<=m;i++){
ll g=gcd(ans[i].a,ans[i].b);
printf("%lld/%lldn",ans[i].a/g,ans[i].b/g);
}
return 0;
}
字符串
字典树
#include
using namespace std;
#define PII pair
typedef long long ll;
const int maxn = 1e3 + 7;
const int N = 4e6 + 7;
char mp[maxn][maxn];
char str[maxn],t[maxn];
int n,m;
int trie[N][26],idx,val[N];
void insert(char *s,int x)
{
int p = 0,len = strlen(s);
for(int i = 0;i < len;i ++){
int ch = s[i] - 'a';
if(!trie[p][ch]) trie[p][ch] = ++idx;
p = trie[p][ch];
}
val[p] = x;
}
int query(char *s)
{
int p = 0,len = strlen(s);
for(int i = 0;i < len;i ++){
int ch = s[i] - 'a';
p = trie[p][ch];
if(!p) return -1;
}
if(val[p]) return val[p];
else return -1;
}
void init()
{
for(int i = 0;i <= idx;i ++){
memset(trie[i],0,sizeof(trie[i]));
val[i] = 0;
}
idx = 0;
}
int main()
{
int tt;scanf("%d",&tt);
while(tt--){
init();
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++){
scanf("%s",mp[i]+1);
}
while(m--){
int x;scanf("%s%d",str,&x);
insert(str,x);
}
int flag = 0;ll sum = 0;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++ ){
int len = 0;
if(mp[i][j] == '#') continue;
while(mp[i][j] != '#' && j <= n){
t[len++] = mp[i][j];
j++;
}
t[len] = ' ';
int ans = query(t);
if(ans == -1) flag = 1;
else sum += ans;
}
}
for(int j=1;j<=n;j++){
for(int i=1;i<=n;i++){
int len = 0;
if(mp[i][j] == '#') continue;
while(mp[i][j] !='#'&& i <= n){
t[len++] = mp[i][j];
i++;
}
t[len] = ' ';
int ans = query(t);
if(ans == -1) flag = 1;
else sum += ans;
}
}
if(flag) printf("-1n");
else printf("%lldn",sum);
}
}
字符串hash
#include
#include
using namespace std;
typedef unsigned long long ULL;
const int N=1e6+10,M=131;
int n,m;
char str[N];
ULL p[N],h[N];
ULL get(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
cin>>n>>m;
cin>>str+1;
p[0]=1;
for(int i=1;i<=n;i++)
{
h[i]=h[i-1]*M+str[i];
p[i]=p[i-1]*M;
}
while(m--)
{
int l1,r1,l2,r2;
cin>>l1>>r1>>l2>>r2;
if(get(l1,r1)==get(l2,r2)) puts("Yes");
else
puts("No");
}
return 0;
}
图论
图的连通子图
#include
const int N=1005;
using namespace std;
vector t[N];
int vis[N]={0};
void dfs(int k)
{
for(int i=0;i>n>>m;
int a,b;//边所连接的两个顶点
for(int i=1;i<=m;i++)
{
cin>>a>>b;
t[a].push_back(b);
t[b].push_back(a);
}
int ans=0;//记录连通块数量
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
vis[i]=1;
dfs(i);
ans++;
}
}
cout<
using namespace std;
const int maxn = 3e5 + 3;
int edge[maxn][maxn];
vector t[maxn];
int pre[maxn], root[maxn];
void init(int nn)
{
for (int i = 1; i <= nn; i++)
pre[i] = i;
}
int find(int x)
{
int f = x;
while (x != pre[x]) //找到x的父节点
x = pre[x];
int j;
while (f != pre[f]) //依次将x上面的节点的父节点赋为x;
{
j = f;
f = pre[f];
pre[j] = x;
}
return x;
}
void merge(int a, int b)
{
int t1, t2;
t1 = find(a);
t2 = find(b);
if (t1 != t2)
{
pre[t2] = t1;
}
}
int block(int nn)
{
int ans = 0;
for (int i = 1; i <= nn; i++)
root[pre[i]] = 1;
for (int i = 1; i <= nn; i++)
ans += root[i];
return ans;
}
int main()
{
int n, m;
cin >> n >> m;
init(n);
for (int i = 1; i <= m; i++)
{
int a,b;
scanf("%d%d",&a,&b);
t[a].push_back(b);
t[b].push_back(a);
// merge(a, b);
}
for (int i = 1; i <= n; i++)
{
vector::iterator it;
for(it=t[i].begin();it!=t[i].size())
printf("%d",block(n));
}
}
// void init(int nn)
// {
// for(int i=1;i<=nn;i++)
// pre[i]=i;
// }
// int find(int x)
// {
// int f=x;
// while(x!=pre[x])//找到x的父节点
// x=pre[x];
// int j;
// while(f!=pre[f])//依次将x上面的节点的父节点赋为x;
// {
// j=f;
// f= pre[f];
// pre[j]=x;
// }
// return x;
// }
// void merge(int a,int b)
// {
// int t1,t2;
// t1=find(a);
// t2=find(b);
// if(t1!=t2)
// {
// pre[t2]=t1;
// }
// }
// int block(int nn)
// {
// int ans=0;
// for(int i=1;i<=nn;i++)
// root[pre[i]]=1;
// for(int i=1;i<=nn;i++)
// ans+=root[i];
// return ans;
// }
// int main()
// {
// scanf("%d%d",&n,&m);
// int a,b;//边所连接的两个顶点
// init(n);
// for(int i=1;i<=m;i++)
// {
// scanf("%d%d",&a,&b);
// t[a].push_back(b);
// t[b].push_back(a);
// merge(a,b);
// }
// printf("%d",block(n));
// return 0;
// }