queue<int>q;
int n;
int main() {
//  freopen(".in", "r", stdin);
//  freopen(".out", "w", stdout);
  n=read();
  for (int i=1;i<=n;i++) 
  {
    int opt=read();
    if(opt==1){
      int x=read();
      q.push(x);
    }
    else {
      printf("%d\n",q.front());
      q.pop();
    }
  } 
  fclose(stdin);
  fclose(stdout);
  return 0;
}
int st[B], head=0, tail=0, n;
int main() {
//  freopen(".in", "r", stdin);
//  freopen(".out", "w", stdout);
  n=read();
  for (int i=1;i<=n;i++)
  {
    int opt=read();
    if(opt==1)
    {
      int x=read();
      st[++head]=x;
    }
    else{
      printf("%d\n", st[head]);
      head--;
    }
  }
  fclose(stdin);
  fclose(stdout);
  return 0;
}
/*暴力O(n^2)*/
for (int a=1;a<=n-k+1;i++)
{
	int ans=oo;
	for (int b=0;b<k;b++)
	{
		ans=min(ans,z[a+b]);
	}
	printf("%d\n",ans);
}
本质:在前面删一个数,从后面加一个数。队列+最小值
样例
1 3 -1 -3 5 3 6 7, 3
要求最小值,维护单调递增的,
不单调的本质就是最后的数和他不是递增的,所以扔掉就好了,
保持单调递增根最小值有啥关系呢?
单调队列中队首就是我们需要的最小值,维护区间长度就是判断队尾和队首是否存在来维护即可
int z[B], n;
struct monotone_queue//单调递增
{
	int head,tail;
	int q[233333];
	monotone_queue()
	{
	head=1,tail=0;
	}
	void push(int p)
	{
		while (head<=tail && z[q[tail]] >= z[p]) tail--;
		q[++tail]=p;
	}
	int front (){
	 return q[head];
	}
	void pop()
	{
		head++;
	}
}q;
int main()
{
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++)
	scanf("%d",&z[i]);
	for (int i=1;i<=k;i++)
		q.push(i);//放入队列的是坐标
	printf("%d\n", z[q.front()]);
	for (int a=k+1;a<=n;a++)
	{
		q.push(a);
		if (q.front()==a-k) q.pop();
		printf("%d\n", z[q.front()]);
	}
}
\(O(nlogn)\)
笔记
如果 \(l=1\) 那么怎么找右 \(r\);
int n, k;
int z[23333];
int l=1,r=1;
int sum=z[1];
while(sum<k)
{
	r++;
	sum+==z[r];
}
ans=min(ans, l-r+1)// 左端点为1时,满足条件区间时多少
那么 \(l=2\) 时呢,同理
那么请问,\(r1,r2\) 之间有什么关系 \(r2>r1\),这里指的是坐标
int n, k;
int z[23333];
int l=1,r=1;
int sum=z[1];
for (int l=1,r=1,sum=z[l];r>=n;)
{
    while(r<n && sum<k)
    {
        r++;
        sum+=z[r];
    }
    if(sum>=k) ans=min(ans, r-l+1);
    else break;
    sum-=z[l];
    l++;
}
复杂度是 \(O(n)\) 每个元素只会被加入一次和出队一次,而且队首和队尾循环时独立的并不冲突,所以总的复杂度为 \(O(n)\),
共同性:当区间左端点右移的时候,右端点也一定右移,
双端对列 \(deque\)
include <deque>
void push(int p)
{
	while (q.size() && z[q.back()] >= z[p])
		q.pop_back();
	q.push_back();
}
int main()
{
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++)
	scanf("%d",&z[i]);
	for (int i=1;i<=k;i++)
		q.push(i);//放入队列的是坐标
	printf("%d\n", z[q.front()]);
	for (int a=k+1;a<=n;a++)
	{
		q.push(a);
		if (q.front()==a-k) q.pop_front();
		printf("%d\n", z[q.front()]);
	}
}
大根堆-priority_queue<int> head
小根堆-将数字取个负数(相反数)
一 如何构造二叉树
二 如何完成堆
大根堆:任何一个点的值都不小于儿子的值
只能删掉最大值!
srtuct heap{
	int n;//元素个数
	int z[2333333];//村原属;
	heap()
	{
		n=0;
	}
	
	int size()
	{
		return n;
	}
	int push()//加入x
	{
		n++;
		z[n]=x;
		int p=n;
		while (p!=1)
		{
			int f=p/2;
			if (z[f]<z[p])//父亲节点是p/2
			{
				swap(z[f],z[p]);
	               p=f;//一直换
			}
			else break;
		}
	}
	int pop()//删除最大值
	{
		swap([z[1],z[n]]);
        n--;//保证树的形态没改变,但是堆的性质没了,所以就需要头不断的向下换
        
        int p=1;
        while (p*2<=n)
        {
            int pp=p*2;//比较两个儿子的大小
            if (pp+1 <= n && z[pp+1] > z[pp]) pp+=1;
            if (z[p] < z[pp])
            {
                swap(z[p], z[pp]);
                p=pp;
            }
            else break;
        }
	}
	int top()
	{
		return z[1];
	}
}
有 \(N\) 个数 \(a_1,a_2...,a_n\),
- 将 \(a_i\) 加上 \(v\);
- 询问 \([l,r]\) 区间和
超级快,常数比较小,解决数据小的,且功能小;
\(lowbit(x)=2^y\) 得到数中最多的 \(2^n\)
\(y_i\) 从 \(i\) 点往下走能走到 \(z\) 位置的和;
\(y_i=z_i+z_{i-1}...+z_{i-lowbit(i)+1}\)
所以询问 \([l,r]\) 和就是前缀和,就是 \([1,r]-[1,l-1]\)
那么怎么询问 \([1,p]\) 和?
#define lb(x) x&(-x)
int n, y[23333];
void modify(int p, int v)
{
	for (;p<=n;p+=lb(p)) y[p]+=v;
}
int query(int p)
{
	int ans=0;
	for (;p-=lb(p);) ans+=y[p];
	return ans;
}
int main()
{
	scanf("%d",&n);
    //发一预处理
    for (int a=1;a<=n;a+=2)
        	lb[a]=1;
    for (int a=1;a<=n/2;a++)
        	lb[a*2]=lb[a]*2;
	for (int i=1;i<=n;i++)
	{
		int v;
		scanf("%d",&v);
		modify(a,v);
	}
	scanf("%d",&m);
	for (int i=1;i<=m;i++)
	{
		int p, v;
		modify(p,v);
		query(p);
	}
}
单点询问,区间修改
差分的思想就将单点询问转换成区间询问
有多少对逆序对?
对于一个数 \(a_i\) 他能产生的逆序对就是比前面小的,比后面大的即可,
那么先考虑只有前面的
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define lb(x) x&(-x)
using namespace std;
const int A = 1e5 + 11;
const int B = 1e8 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for ( ; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1;
  for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}
int m, y[B], z[B],n;
void updata(int x,int v){
  for (;x<=n;x+=lb(x)) y[x]+=v;
}
int query(int x)
{
  int ans=0;
  for (;x;x-=lb(x)) ans+=y[x];
  return ans;
}
  
int main() {
//  freopen(".in", "r", stdin);
//  freopen(".out", "w", stdout);
  m=read();
  for (int i=1;i<=m;i++)
    scanf("%d",&z[i]), n=max(n,z[i]);
  int ans=0;
  for (int i=1;i<=m;i++)
  {
    updata(z[i],1);
    ans+=query(n)-query(z[i]);
  }
  printf("%d\n",ans);
  fclose(stdin);
  fclose(stdout);
  return 0;
}
1-N的无序排列,做旋转置换,问怎样的置换能够使得得到的逆序对最小
int m, y[B], z[B],n;
void updata(int x,int v){
  for (;x<=n;x+=lb(x)) y[x]+=v;
}
int query(int x)
{
  int ans=0;
  for (;x;x-=lb(x)) ans+=y[x];
  return ans;
}
  
int main() {
//  freopen(".in", "r", stdin);
//  freopen(".out", "w", stdout);
  n=read();
  int ans=0;
  for (int i=1;i<=n;i++) updata(i,1);
  for (int i=1;i<=n;i++)
  {
    cin>>z[i];
    updata(z[i]+1,-1);
    ans+=query(z[i]+1);
  }
  int sum=ans;
  for (int i=1;i<=n;i++)
  {
    ans+=(-z[i]+n-z[i]-1);
    if (ans<sum)
      sum=ans;
  }
  cout << sum;
}
    
原文:https://www.cnblogs.com/lToZvTe/p/14412382.html