【莫队/树上莫队/回滚莫队】原理详解及例题:小B的询问(普通莫队),Count on a tree II(树上莫队),kangaroos(回滚莫队)

文章目录

  • 问题引入
  • 介绍莫队算法及其实现过程
  • 时间复杂度
  • 莫队算法适用范围
  • 莫队奇偶优化
  • 普通莫队:小B的询问
  • 树上莫队:SP10707 COT2 - Count on a tree II
  • 回滚莫队:[PA2011]Kangaroos

upd:2021-08-11:重新对博客进行了外观美化修正,以及新增树上莫队
upd:2021-08-19:新增回滚莫队

问题引入

给定一个大小为NNN的数组,数组中所有元素的大小≤N\le NN。你需要回答MMM个查询。
每个查询的形式是L,RL,RL,R。你需要回答在范围[L,R][L,R][L,R]中至少重复222次的数字的个数


如果按照以往的想法,就会是O(n2)O(n^2)O(n2)的暴力枚举

for ( int i = 1;i <= Q;i ++ ) {scanf ( "%d %d", &l, &r );for ( int j = l;j <= r;j ++ ) {count[a[j]] ++;if ( count[a[j]] == 3 )result ++;}}

就算加一些优化,用l,rl,rl,r采取指针转移,但总归上还是在[1,n][1,n][1,n]区间内进行移动

最坏多半也是逼近于O(n2)O(n^2)O(n2)

void add ( int x ) {count[a[x]] ++;if ( count[a[x]] == 3 )result ++;
}
void removed ( int x ) {count[a[x]] --;if ( count[a[x]] == 2 )result --;
}
for ( int i = 1;i <= m;i ++ ) {scanf ( "%d %d", &l, &r );while ( curl < l )removed ( curl ++ );while ( curl > l )add ( -- curl );while ( curr > r )removed ( curr -- );while ( curr < r )add ( ++ curr );printf ( "%d\n", result );
}

add ​添加该位置的元素到当前集合内,并且更新答案

remove 从当前集合内删除该位置的元素,并更新答案


那么这个时候莫队算法就重磅登场了

在这里插入图片描述

为什么叫做莫队算法呢?

据说算法是由之前的国家队队长莫涛发明的,他的队友平日里称他为莫队,所以称之为莫队算法


介绍莫队算法及其实现过程

莫队算法就是一个离线算法,仅仅调整了处理查询的顺序

实现过程如下:

  • 将给定的输入数组分为n\sqrt{n}n​​​​​块。每一块的大小为 nn\frac{n}{\sqrt{n}}nn

    每个LLL​​​​落入其中的一块,每个RRR也落入其中的一块

    如果某查询的LLL​​​落在第iii​​块中,则该查询属于第iii​块​​

  • 所有的询问首先按照所在块的编号升序排列(所在块的编号是指询问的L属于的块

    如果编号相同,则按R值升序排列

  • 莫队算法将依次处理第111块中的查询,然后处理第222.........直到最后一块

    有很多的查询属于同一块

e.g.

假设我们有333​​个大小为333​的块(0−2,3−5,6−8)(0-2,3-5,6-8)(02,35,68){0,3}{1,7}{2,8}{7,8}{4,8}{4,4}{1,2}\{0,3\} \{1, 7\} \{2, 8\} \{7, 8\} \{4, 8\} \{4, 4\} \{1, 2\}{0,3}{1,7}{2,8}{7,8}{4,8}{4,4}{1,2}

先根据所在块的编号重新排列它们

  • 111块:{0,3}{1,7}{2,8}{1,2}\{0, 3\} \{1, 7\} \{2, 8\} \{1, 2\}{0,3}{1,7}{2,8}{1,2}
  • 222块:{4,8}{4,4}\{4, 8\} \{4, 4\}{4,8}{4,4}
  • 333​块:{7,8}\{7, 8\}{7,8}

接下来按照R的值重新排列

  • 第一块:{1,2}{0,3}{1,7}{2,8}\{1, 2\} \{0, 3\} \{1, 7\} \{2, 8\}{1,2}{0,3}{1,7}{2,8}
  • 第二块:{4,4}{4,8}\{4, 4\} \{4, 8\}{4,4}{4,8}
  • 第三块: {7,8}\{7, 8\}{7,8}

上述过程只是重新排列了查询的顺序
在这里插入图片描述


时间复杂度

我们说了这么多,选用莫队算法无非就是想把时间复杂度给降下来

接下来我们来看看真正莫队的时间复杂度是多少,其实我看了很多博客也是有点懵逼

上面的代码就是起一个铺垫作用,所有查询的复杂性是由444个``while`循环决定的

222​​个while循环可以理解为左指针curl的移动总量

222​​个 while循环可以理解为右指针curr的移动总量

这两者的和将是总复杂性


先算右指针

对于每个块,查询是递增的顺序排序,所以右指针curr按照递增的顺序移动

在下一个块的开始时,指针可能在最右端,将移动到下一个块中的最小的RRR

又可以从本块最左端移动到最右端

这意味着对于一个给定的块,右指针移动的量是O(n)O(n)O(n)(curr可以从111跑到最后的nnn

我们有O(n)O(\sqrt{n})O(n)​块,所以总共是O(nn)O(n\sqrt{n})O(nn)​​


接下来看看左指针怎样移动

对于每个块,所有查询的左指针落在同一个块中,从一个查询移动到下一个查询左指针会移动

但由于前一个LLL​与下一个LLL在同一块中,此移动是O(n)O(\sqrt{n})O(n)​​​(块的大小)

在每一块中左指针的移动总量是O(Qn)O(Q\sqrt{n})O(Qn)​​,(QQQ是落在那个块的查询的数量)

对于所有的块,总的复杂度为O(m∗n)O(m∗\sqrt{n})O(mn)​​


综上,总复杂度为O((n+m)∗n)=O(n∗n)O((n+m)∗\sqrt{n})=O(n∗\sqrt n)O((n+m)n)=O(nn)

实在无法理解就跳过吧(如果有通俗易懂的解释欢迎评论)

莫队算法适用范围

首先莫队算法是一个离线算法,所以如果问题是在线操作带修或者强制特殊的顺序

莫队就失去了它的效应
在这里插入图片描述


其次一个重要的限制性:addremove的操作

当有些题目的addremove耗时很大,O(N)O(\sqrt N)O(N)​​​​时就应该思考能否卡过

因为莫队本身就是一种优美的暴力而已

但是还是有很大一部分区间查询的题可以由莫队进行完成

莫队奇偶优化

sqt = sqrt( n )
bool cmp( node x, node y ) {return ( x.l / sqt == y.l / sqt ) ? ( ( ( x.l / sqt ) & 1 ) ? x.r < y.r : x.r > y.r ) : x.l < y.l;
}

在这里插入图片描述

普通莫队:小B的询问

小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,
每个询问给定一个区间[L…R],求Sigma(c(i)^2)的值,
其中i的值从1到K,其中c(i)表示数字i在[L…R]中的重复次数。
小B请你帮助他回答询问。

输入格式
第一行,三个整数N、M、K。
第二行,N个整数,表示小B的序列。
接下来的M行,每行两个整数L、R。
输出格式
M行,每行一个整数,其中第i行的整数表示第i个询问的答案。

输入输出样例
输入
6 4 3
1 3 2 1 1 3
1 4
2 6
3 5
5 6
输出
6
9
5
2
说明/提示
对于全部的数据,1<=N、M、K<=50000

简单题解

说了是算法模板入门题,肯定不会把你拒之门外,还是要让你摸摸门的

这个题就是要简单处理一下∑ci2∑c_i^2ci2​,当ci±1c_i±1ci±1​时,答案会发生怎样的转化?

完全平方公式大家都会吧!!!👇

(c[i]−1)2=c[i]2−2∗c[i]+1(c[i]-1)^2=c[i]^2-2*c[i]+1(c[i]1)2=c[i]22c[i]+1

(c[i]+1)2=c[i]2+2∗c[i]+1(c[i]+1)^2=c[i]^2+2*c[i]+1(c[i]+1)2=c[i]2+2c[i]+1

#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
#define LL l;ong long
#define MAXN 50005
struct node {int l, r, num;
}G[MAXN];
int n, m, k, apart, curl = 1, curr; 
int a[MAXN], cnt[MAXN];
LL result;
LL ans[MAXN];bool cmp ( node x, node y ) {return ( x.l / apart == y.l / apart ) ? x.r < y.r : x.l < y.l;
}void add ( int x ) {result += ( cnt[a[x]] << 1 ) + 1;cnt[a[x]] ++;
}
void removed ( int x ) {result -= ( cnt[a[x]] << 1 ) - 1;cnt[a[x]] --;
}int main() {scanf ( "%d %d %d", &n, &m, &k );for ( int i = 1;i <= n;i ++ )scanf ( "%d", &a[i] );apart = sqrt ( n );for ( int i = 1;i <= m;i ++ ) {scanf ( "%d %d", &G[i].l, &G[i].r );G[i].num = i;}sort ( G + 1, G + m + 1, cmp );for ( int i = 1;i <= m;i ++ ) {int l = G[i].l, r = G[i].r;while ( curl < l ) {removed ( curl ++ );}while ( curl > l ) {add ( -- curl );}while ( curr > r ) {removed ( curr -- );}while ( curr < r ) {add ( ++ curr );}ans[G[i].num] = result;}for ( int i = 1;i <= m;i ++ )printf ( "%lld\n", ans[i] );return 0;
}

树上莫队:SP10707 COT2 - Count on a tree II

顾名思义就是把序列莫队搬到树上实现

分块的大小以及移动的操作与序列莫队无差别

唯一的区别就在于询问的l,r

在树上莫队询问的l,rl,rl,r​要用欧拉序进行重新编号

e.g.

fasdfa

原图的欧拉序为1,2,4,6,6,7,7,5,5,4,2,3,3,1,对于点iiili:l_i:li: 第一次访问iiiri:r_i:ri: 最后一次访问iii

树上莫队就是用欧拉序的li,ril_i,r_ili,ri代替访问的iii

对于查询的(u,v)有两种情况

  • 是直系祖先关系(假设uuuvvv的祖先)

    e.g. : u=2,v=7u=2,v=7u=2,v=7​​,拿出[lu,lv][l_u,l_v][lu,lv]​代替u,vu,vu,v

    欧拉序为2,4,6,6,7

  • 不隶属同一棵子树(假设lu<lvl_u<l_vlu<lv

    e.g : u=7,v=3u=7,v=3u=7,v=3​,拿出[ru,lv][r_u,l_v][ru,lv]

    欧拉序为7,5,5,4,2,3

不在路径上的点经过了恰好两次,真正在路径上的点都恰好只出现一次;对于不同子树的两点需要额外加上lca

source

#include <cmath>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 40005
#define maxm 100005
vector < int > G[maxn];
int n, Q, B, cnt, ans;
bool vis[maxn];
int c[maxn], MS[maxn], tot[maxn], ret[maxm];
int dep[maxn], l[maxn], r[maxn], id[maxn << 1];
int f[maxn][20];
struct node {int l, r, id, lca;
}q[maxm];void dfs( int u, int fa ) {dep[u] = dep[fa] + 1, l[u] = ++ cnt, id[cnt] = u;for( int i = 1;i <= 16;i ++ )f[u][i] = f[f[u][i - 1]][i - 1];for( auto v : G[u] ) {if( v == fa ) continue;else f[v][0] = u, dfs( v, u );}r[u] = ++ cnt, id[cnt] = u;
}int get_lca( int u, int v ) {if( dep[u] < dep[v] ) swap( u, v );for( int i = 16;~ i;i -- )if( dep[f[u][i]] >= dep[v] ) u = f[u][i];if( u == v ) return u;for( int i = 16;~ i;i -- )if( f[u][i] != f[v][i] ) u = f[u][i], v = f[v][i];return f[u][0];
}void Delete( int x ) { if( -- tot[c[x]] == 0 ) ans --; }void Insert( int x ) { if( ++ tot[c[x]] == 1 ) ans ++; }void modify( int x ) { vis[x] ? Delete( x ) : Insert( x ); vis[x] ^= 1; }int main() {scanf( "%d %d", &n, &Q );for( int i = 1;i <= n;i ++ )scanf( "%d", &c[i] ), MS[i] = c[i];sort( MS + 1, MS + n + 1 );int m = unique( MS + 1, MS + n + 1 ) - MS - 1;for( int i = 1;i <= n;i ++ )c[i] = lower_bound( MS + 1, MS + m + 1, c[i] ) - MS;B = sqrt( n );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs( 1, 0 );for( int i = 1, u, v;i <= Q;i ++ ) {scanf( "%d %d", &u, &v );q[i].id = i;if( l[u] > l[v] ) swap( u, v );int lca = get_lca( u, v );if( u == lca ) q[i].l = l[u], q[i].r = l[v], q[i].lca = 0;else q[i].l = r[u], q[i].r = l[v], q[i].lca = lca;}sort( q + 1, q + Q + 1, []( node x, node y ) { return ( x.l / B == y.l / B ) ? ( x.r < y.r ) : ( x.l < y.l ); } );int curl = 1, curr = 0;for( int i = 1;i <= Q;i ++ ) {while( curl < q[i].l ) modify( id[curl ++] );while( q[i].l < curl ) modify( id[-- curl] );while( curr < q[i].r ) modify( id[++ curr] );while( q[i].r < curr ) modify( id[curr --] );if( q[i].lca ) modify( q[i].lca );ret[q[i].id] = ans;if( q[i].lca ) modify( q[i].lca );}for( int i = 1;i <= Q;i ++ )printf( "%d\n", ret[i] );
}

回滚莫队:[PA2011]Kangaroos

普通莫队是能做到快速增添和删减操作的

但有些题目在区间转移时,可能会出现增加或者删除无法实现的问题

在只有增加不可实现或者只有删除不可实现的时候,就可以使用回滚莫队

同样在O(nn)O(n\sqrt n)O(nn)的时间内解决问题

回滚莫队的核心思想就是既然只能实现一个操作,那么就只使用一个操作,剩下的交给回滚解决

回滚莫队分为只使用增加操作的回滚莫队和只使用删除操作的回滚莫队

以只使用添加操作的回滚莫队为例

  • 首先仍是按照区间左端点分块排序,然后右端点为第二关键字
  • 枚举区间左端点的块
    • 对于询问的左右端点都在同一区间的直接暴力做
    • 将左端点都在该块的按右端点升序排序
    • 每次都是右端点右移,加入答案
    • 左端点每次都回滚到这个块的末尾,然后暴力的往前移到本次询问的左端点处,记录这一路上的答案,但是不像右端点一样是永久的
      再回退到块末尾,这样的时间复杂度,mmm个询问,每次询问左端点最多暴力移整个区间n\sqrt nn,还是根号级别的复杂度
  • 到下一块的时候,l,rl,rl,r一起遍历了整个区间,扔掉所有的标记那些,然后手动重置为初始局面

只支持删除的话,我想应该就是右端点rrr递减,不断前移,然后还是左端点lll在块中反复移动清空

可以看一下这道题→\rightarrow 回滚莫队的例题——历史研究

Kangaroos比较难一点

区间过大,实际上区间相交只关系左右端点的大小关系,所以先离散化区间的端点,最多只有2n2n2n

然后按询问左端点分块,将询问挂到块上

接下来就是回滚莫队问题了

这道题主要是要维护最大连续区间

每次将新增区间的下标扔进去的时候,更新

可以用线段树维护最大连续区间,但是实际上可以用l[],r[]\rm l[],r[]l[],r[]数组来维护左右端点,省去log\rm loglog

这只是简单口胡,看不懂可以看代码,代码里有详细注释

#include <cmath>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 200005
#define maxB 320
struct node {int l, r, id;node(){}node( int L, int R, int ID ) {l = L, r = R, id = ID;}
}t[maxn];
struct Node {int val, id;Node(){}Node( int Val, int ID ) {val = Val, id = ID;}
}x[maxn];
vector < node > q[maxB];
int n, m, ans, top;
int block[maxn], L[maxB], R[maxB], l[maxn], r[maxn], ret[maxn];bool operator < ( Node s, Node t ) {return s.val == t.val ? s.id < t.id : s.val < t.val;
}struct opt {//记录操作前的相关信息 方便回滚 //flag 0:左 1:右 记录被更改的是哪边 int flag, pos, lst, ans;opt(){}opt( int  Flag, int Pos, int Lst, int Ans ) {flag = Flag, pos = Pos, lst = Lst, ans = Ans;}
}s[maxn << 4];
//l[i]:在当前已加入区间中i区间所能连的最左边区间下标 -> [l(i),i]的所有区间都与当前查询区间有交 
//r[i]:在当前已加入区间中i区间所能连的最右边区间下标 -> [i,r(i)]的所有区间都与当前查询区间有交 
void add( int i ) {if( l[i] || r[i] ) return;//已经算过了i的贡献 if( ! l[i - 1] and ! r[i + 1] ) {//左右的区间都还没有被加进来//只能自己这一个区间 长度为1 s[++ top] = opt( 0, i, l[i], ans );s[++ top] = opt( 1, i, r[i], ans );l[i] = r[i] = i, ans = max( ans, 1 );}else if( ! l[i - 1] ) {//i+1的区间被加入了 可以往左延伸和i接上 s[++ top] = opt( 0, r[i + 1], l[r[i + 1]], ans );s[++ top] = opt( 1, i, r[i], ans );r[i] = r[i + 1], l[r[i + 1]] = i;ans = max( ans, r[i] - i + 1 );}else if( ! r[i + 1] ) {//i-1的区间被加入了 可以往右延伸和i接上 s[++ top] = opt( 1, l[i - 1], r[l[i - 1]], ans );s[++ top] = opt( 0, i, l[i], ans );l[i] = l[i - 1], r[l[i - 1]] = i;ans = max( ans, i - l[i] + 1 );}else {//i-1 i+1都被加入 直接左右连接拼起来 s[++ top] = opt( 0, r[i + 1], l[r[i + 1]], ans );s[++ top] = opt( 1, l[i - 1], r[l[i - 1]], ans );s[++ top] = opt( 0, i, l[i], ans );s[++ top] = opt( 1, i, r[i], ans );//都连起来了 也没有i什么事了 所以随便记录i的一边l/r有值 下次就可以在第一个if语句直接return l[r[i + 1]] = l[i - 1], r[l[i - 1]] = r[i + 1], l[i] = r[i] = i;ans = max( ans, r[i + 1] - l[i - 1] + 1 );		}
}void remove( int lst ) {while( top > lst ) {if( ! s[top].flag ) l[s[top].pos] = s[top].lst;else r[s[top].pos] = s[top].lst;ans = s[top --].ans; }
}void solve( int id ) {remove( 0 );//移动到新块 莫队里的东西清空 for( int i = 1;i <= n;i ++ ) if( t[i].l < L[id] && R[id] < t[i].r )//完全覆盖该块且不在块内的区间一定会对块内所挂询问产生贡献 add( t[i].id );sort( q[id].begin(), q[id].end(), []( node x, node y ) { return x.r < y.r; } );//将块内询问按照右端点排序 只增加的回滚莫队 int lst = top;for( node now : q[id] ) //计算整个区间都在块内的询问的答案if( now.r > R[id] ) continue;else {for( int i = L[id];i <= R[id];i ++ )if( now.l <= t[x[i].id].r && t[x[i].id].l <= now.r )//与查询区间有交 可能会为答案贡献的区间 add( x[i].id );ret[now.id] = ans;remove( lst ); }remove( 0 );int cur = R[id];//处理r在其他块递增的询问 先把指针拨到块的最后for( int i = 1;i <= n;i ++ )if( t[i].l <= R[id] && R[id] <= t[i].r )//一定会与后面的查询有交点 R[id]add( t[i].id );for( node now : q[id] )if( now.r <= R[id] ) continue;else {while( cur < now.r ) add( x[++ cur].id );lst = top;for( int i = R[id];i >= now.l;i -- )//回滚莫队 滚到当前询问的左端 add( x[i].id );ret[now.id] = ans;remove( lst );//返回 回滚 抵消 }
}int main() {scanf( "%d %d", &n, &m );for( int i = 1, l, r;i <= n;i ++ ) {scanf( "%d %d", &l, &r );x[i] = Node( l, i );x[i + n] = Node( r, i );t[i] = node( l, r, i );}//为了块的大小能开出来 1e9首先要离散化 sort( x + 1, x + ( n << 1 ) + 1 );for( int i = 1;i <= n;i ++ ) {t[i].l = lower_bound( x + 1, x + ( n << 1 | 1 ), Node( t[i].l, 0 ) ) - x;t[i].r = upper_bound( x + 1, x + ( n << 1 | 1 ), Node( t[i].r, 1e9 ) ) - x - 1;}int N = n << 1;int B = sqrt( N );for( int i = 1;i <= N;i ++ )block[i] = ( i - 1 ) / B + 1;//L,R 记录块的左右端点 for( int i = N;i;i -- ) L[block[i]] = i;for( int i = 1;i <= N;i ++ ) R[block[i]] = i;for( int i = 1, l, r;i <= m;i ++ ) {scanf( "%d %d", &l, &r );l = lower_bound( x + 1, x + ( n << 1 | 1 ), Node( l, 0 ) ) - x;r = upper_bound( x + 1, x + ( n << 1 | 1 ), Node( r, 1e9 ) ) - x - 1;q[block[l]].push_back( node( l, r, i ) );}for( int i = 1;i <= block[N];i ++ )if( ! q[i].empty() )solve( i );for( int i = 1;i <= m;i ++ )printf( "%d\n", ret[i] );return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318200.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微软 2018 开源大事记

从微软公开宣布 "Microsoft love linux" 那一刻起&#xff0c;过去的几年里&#xff0c;微软积极拥抱开源的举动我们有目共睹&#xff0c;即便有过"Linux is a cancer"这种真香警告的 flag&#xff0c;但不得不承认的是&#xff0c;微软一系列“拥抱开源”…

模板:二叉搜索树平衡树

文章目录前言二叉搜索树代码treap代码splay开点旋转splay插入查找第k大元素查找给定元素的排名前驱&后继删除完整代码练习总结前言 终于开始学这个东西了 看了好几篇博客才找到一篇可读的qwq 我曾经还以为线段树码量大…我真傻&#xff0c;真的 所谓平衡树&#xff0c;就是…

P2486 [SDOI2011]染色

P2486 [SDOI2011]染色 题意&#xff1a; 题解&#xff1a; 与一般的树链剖分相比&#xff0c;不同点在于查询的不是路径上颜色的数量而是颜色段的数量 对于两个颜色段&#xff0c;112和221&#xff0c;两个颜色段数量都是2 如果合在一起颜色段的数量就是3&#xff0c;因为左边…

牛客网CSP-S提高组赛前集训营1题解(仓鼠的石子游戏 [博弈论] + 乃爱与城市的拥挤程度 [树上DP] + 小w的魔术扑克[dfs + 离线])

文章目录T1&#xff1a;仓鼠的石子游戏题目题解代码实现T2&#xff1a;乃爱与城市拥挤程度题目题解代码实现T3&#xff1a;小w的魔术扑克题目题解代码实现T1&#xff1a;仓鼠的石子游戏 题目 仓鼠和兔子被禁止玩电脑&#xff0c;无聊的他们跑到一块空地上&#xff0c;空地上有…

使用PerfView监测.NET程序性能(二):Perfview的使用

在上一篇博客使用PerfView监测.NET程序性能&#xff08;一&#xff09;&#xff1a;Event Trace for Windows 中&#xff0c;我们了解了对Windows及应用程序进行性能分析的基础&#xff1a;Event Trace for Windows (ETW)。现在来看看基于ETW的性能分析工具——Perfview.exePer…

学习有向图和无向图的强连通分量(基本概念+割点+点双联通分量+桥+边双连通分量+全套模板【Tarjan】)

最近总是考到Tarjan&#xff0c;让我措手不及基本概念割点以及点双连通分量Tarjan法求割点推导过程代码实现Tarjan法求点双连通分量推导过程代码实现有向图的Tarjan缩点桥与边双连通分量Tarjan法求桥理论推导代码实现Tarjan法求边双连通分量理论推导代码实现前言&#xff1a;有…

.NET Core下的Spring Cloud——前言和概述

前言前几年一直在写类似dubbo&#xff0c;Spring Cloud的微服务框架辗辗转转重复了多次&#xff0c;也重构推翻了很多次&#xff0c;其中诞生了“Rabbit.Rpc”,”Go”,”RabbitCloud”等开源项目。其中不乏他人对这些项目的完善。很高兴自己的开源项目能够给他人提供思路和复用…

CF785E Anton and Permutation

CF785E Anton and Permutation 题意&#xff1a; 对于一个长度为 n 的序列进行 k 次操作&#xff0c;每次操作都是交换序列中的某两个数。对于每一个操作&#xff0c;回答当前序列中有多少个逆序对。 1<n<200000 1<q<50000 题解&#xff1a; 动态逆序对&#x…

[ NOIP提高组 2016]愤怒的小鸟(暴搜 + 状压DP)// [SNOI2017]一个简单的询问(莫队)

一次性写两道题T1&#xff1a;一个简单的询问题目题解代码实现T2&#xff1a;愤怒的小鸟题目暴搜题解暴搜代码实现状压DP题解状压DP代码实现T1&#xff1a;一个简单的询问 题目 给你一个长度为 N 的序列 ai ,1≤i≤N&#xff0c;和 q 组询问&#xff0c;每组询问读入 l1,r1,l…

微软发布新的 Azure Pipelines 功能和集成

在最近举行的Connect()大会上&#xff0c;微软发布了几项新功能以及与 Azure Pipelines 的集成&#xff0c;包括 Visual Studio Code 的 Azure Pipelines 扩展、GitHub 版本管理、对 IoT 项目的支持以及 ServiceNow 集成。自从 9 月份推出 Azure Pipelines 以来&#xff0c;这种…

年末展望:Oracle 对 JDK收费和.NET Core 给我们的机遇

2018年就结束了&#xff0c;马上就要迎来2019年&#xff0c;这一年很不平凡&#xff0c;中美贸易战还在继续&#xff0c;IT互联网发生急剧变化&#xff0c;大量互联网公司开始裁员&#xff0c;微软的市值在不断上升 &#xff0c;在互联网公司的市值下跌过程中爬到了第一的位置&…

等比数列三角形 (数论 + 黄金分割点)+ JOISC 2016 Day3 T3 「电报」(基环树 + 拓扑排序)

文章目录T1&#xff1a;等比数列三角形题目题解代码实现T2&#xff1a;电报题目题解代码实现T1&#xff1a;等比数列三角形 题目 求三边都是 ≤n 的整数&#xff0c;且成等比数列的三角形个数 注意三角形面积不能为 0 注意 oeis 中未收录此数列&#xff0c;所以并不需要去搜了…

使用PerfView监测.NET程序性能(三):分组

在上一篇博客使用PerfView监测.NET程序性能&#xff08;二&#xff09;&#xff1a;Perfview的使用中&#xff0c;我们通过Perfview帮助文件中自带的代码来简单使用了Perfview&#xff0c;了解了基本操作。现在来看看Perfview中的分组操作&#xff08;Grouping&#xff09;。分…

【做题记录】构造题

CF468C Hack it! 题意&#xff1a; 令 \(F(x)\) 表示 \(x\) 的各个位上的数字之和&#xff0c;如 \(F(1234)123410\) 。 给定 \(a(a\le 10^{18})\) &#xff0c;请求出任意一组 \(l,r(l,r\le 10^{200})\) &#xff0c;要求满足&#xff1a; \[\sum_{il}^{r}F(i)\pmod{a}0 \]输出…

Star Way To Heaven (prim最小生成树) // [ NOIP提高组 2014]飞扬的小鸟(DP)

文章目录T1&#xff1a;Star Way To Heaven题目题解代码实现T2&#xff1a;飞扬的小鸟题目题解代码实现T1&#xff1a;Star Way To Heaven 题目 小 w 伤心的走上了 Star way to heaven。 到天堂的道路是一个笛卡尔坐标系上一个 n*m 的长方形通道 顶点在 (0,0) 和 (n,m) 。 小…

IdentityServer4-客户端的授权模式原理分析(三)

在学习其他应用场景前&#xff0c;需要了解几个客户端的授权模式。首先了解下本节使用的几个名词Resource Owner&#xff1a;资源拥有者&#xff0c;文中称“user”&#xff1b;Client为第三方客户端&#xff1b;Authorization server为授权服务器&#xff1b;redirection URI&…

[2019 牛客CSP-S提高组赛前集训营4题解] 复读数组(数论)+ 路径计数机(数上DP)+ 排列计数机(线段树+二项式定理)

文章目录T1&#xff1a;复读数组题目题解代码实现T2&#xff1a;路径计数机题目题解代码实现T3&#xff1a;排列计数机题目题解CODET1&#xff1a;复读数组 题目 有一个长为nk的数组&#xff0c;它是由长为n的数组A1,A2,…,An重复k次得到的。 定义这个数组的一个区间的权值为…

微软携手 Docker 打造 CNAB,分布式应用来了!

微软中国MSDN 前天Microsoft Connect(); 2018发布的众多最新科技&#xff0c;都让全球开发者惊艳不已。其中一项最令开发者瞩目并迫不及待——微软联合Docker发布了云本地应用捆绑包&#xff08;Cloud Native Application Bundle&#xff0c;以下简称CNAB&#xff09;&#xff…

[C++]试一试结构体struct node的构造函数

可直接点击跳转到构造函数处结构体概念定义结构体定义结构体及结构体变量结构体变量的特点成员调用成员函数调用结构体的构造函数Upd1Upd2Upd3结构体概念 在实际问题中&#xff0c;一组数据往往具有不同的数据类型。 例如&#xff1a;人口大普查时&#xff0c;需要记录每一个人…

[多校联考-西南大学附中]切面包(线段树/概率与期望)+ Slow Path Finding Algorithm(拓扑排序/DP)+ 分数转化(数论)

文章目录T1&#xff1a;分数转换题目题解代码实现T2&#xff1a;Slow Path Finding Algorithm题目题解代码实现T3&#xff1a;切面包题目题解代码实现T1&#xff1a;分数转换 题目 Time limit: 1.5 seconds Memory limit: 512 megabytes 给定一个十进制小数&#xff0c;请你…