#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <stdio.h>
#include <math.h>

using namespace std;
long long coun[10000];
long long pet[10000];
long long arr[10000];
int full = 0;
vector<long long> graph[10000];
bool binSearch(long long beg, long long end, long long num){
	if (beg == end){
		if (coun[beg] == num)return true;
		else return false;
	}
	if (binSearch(beg, (beg + end) / 2, num))return true;
	else if (binSearch((beg + end) / 2+1,end, num))return true;
	else return false;
}
void dps(int x){
	arr[x] = 1;
	full++;
	for (int i = 0; i < graph[x].size(); i++)
	//for each (long long y in graph[x])
	{
		if (arr[graph[x][i]] == 0)dps(graph[x][i]);
	}
	return;
}
int main(){
	long long n, m;
	long long ans=0;
	cin >> n>>m;
	if (m == 1||n==1){
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; i++){
		coun[i] = 0;
		arr[i] = 0;
	}
	long long a, b;
	for (int i = 0; i < m; i++){
		cin >>a >> b;
		if (a == b){
			pet[a - 1]++;
			graph[a - 1].push_back(b - 1);
		}
		else{
			coun[a - 1]++;
			coun[b - 1]++;
			graph[a - 1].push_back(b - 1);
			graph[b - 1].push_back(a - 1);
		}
	}
	long long num = 0;
	long long sumpet = 0;
	for (int i = 0; i < n; i++){
		if (graph[i].size()>0)num++;
	}
	dps(a-1);
	if (full!=num){
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; i++){
		sumpet += pet[i];
	}
	for (int i = 0; i < n; i++){
		if(coun[i]!=0)ans += coun[i]*(coun[i]-1) / 2;
	}
	ans += sumpet*(m - sumpet) + sumpet*(sumpet - 1) / 2;

	cout << ans;
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <stdio.h>
#include <math.h>

using namespace std;
int coun[1000000];
bool arr[1000000];
int full = 0;
vector<int> graph[1000000];
//bool binSearch(int beg, int end, int num){
//	if (beg == end){
//		if (coun[beg] == num)return true;
//		else return false;
//	}
//	if (binSearch(beg, (beg + end) / 2, num))return true;
//	else if (binSearch((beg + end) / 2+1,end, num))return true;
//	else return false;
//}
void dps(int x){
	arr[x] = false;
	full++;
	for (int i = 0; i < graph[x].size(); i++)
	//for each (int y in graph[x])
	{
		if (arr[graph[x][i]])dps(graph[x][i]);
	}
	return;
}
int main(){
	int n, m;
	long long ans=0;
	cin >> n>>m;
	if (m == 1||n==1){
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; i++){
		coun[i] = 0;
		arr[i] = true;
	}
	int a, b;
	int num = 0;
	int sumpet = 0;
	for (int i = 0; i < m; i++){
		cin >>a >> b;
		if (a == b){
			sumpet++;
			graph[a - 1].push_back(b - 1);
			if (graph[a - 1].size() == graph[a - 1].capacity())graph[a - 1].reserve(graph[a - 1].size() * 2);
		}
		else{
			coun[a - 1]++;
			coun[b - 1]++;
			if (graph[a - 1].size() == graph[a - 1].capacity())graph[a - 1].reserve(graph[a - 1].size() * 2);
			if (graph[b - 1].size() == graph[b - 1].capacity())graph[b - 1].reserve(graph[b - 1].size() * 2);
			graph[a - 1].push_back(b - 1);
			graph[b - 1].push_back(a - 1);
		}
	}
	for (int i = 0; i < n; i++){
		if (graph[i].size()>0)num++;
	}
	dps(a-1);
	if (full!=num){
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; i++){
		if (coun[i] >1)ans += (long long)coun[i] * ((long long)coun[i] - 1) / 2;
	}
	ans += (long long)sumpet*(long long)(m - sumpet) + (long long)sumpet*((long long)sumpet - 1) / 2;

	cout << ans;
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <stdio.h>
#include <math.h>

using namespace std;
long long coun[10000];
long long pet[10000];
long long arr[10000];
int full = 0;
vector<long long> graph[10000];
bool binSearch(long long beg, long long end, long long num){
	if (beg == end){
		if (coun[beg] == num)return true;
		else return false;
	}
	if (binSearch(beg, (beg + end) / 2, num))return true;
	else if (binSearch((beg + end) / 2+1,end, num))return true;
	else return false;
}
void dps(int x){
	arr[x] = 1;
	full++;
	for each (long long y in graph[x])
	{
		if (arr[y] == 0)dps(y);
	}
	return;
}
int main(){
	long long n, m;
	long long ans=0;
	cin >> n>>m;
	if (m == 1||n==1){
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; i++){
		coun[i] = 0;
		arr[i] = 0;
	}
	long long a, b;
	for (int i = 0; i < m; i++){
		cin >>a >> b;
		if (a == b){
			pet[a - 1]++;
			graph[a - 1].push_back(b - 1);
		}
		else{
			coun[a - 1]++;
			coun[b - 1]++;
			graph[a - 1].push_back(b - 1);
			graph[b - 1].push_back(a - 1);
		}
	}
	long long num = 0;
	long long sumpet = 0;
	for (int i = 0; i < n; i++){
		if (graph[i].size()>0)num++;
	}
	dps(a-1);
	if (full!=num){
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; i++){
		sumpet += pet[i];
	}
	for (int i = 0; i < n; i++){
		if(coun[i]!=0)ans += coun[i]*(coun[i]-1) / 2;
	}
	ans += sumpet*(m - sumpet) + sumpet*(sumpet - 1) / 2;

	cout << ans;
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <stdio.h>
#include <math.h>

using namespace std;
long long coun[1000000];
long long arr[1000000];
int full = 0;
vector<long long> graph[1000000];
bool binSearch(long long beg, long long end, long long num){
	if (beg == end){
		if (coun[beg] == num)return true;
		else return false;
	}
	if (binSearch(beg, (beg + end) / 2, num))return true;
	else if (binSearch((beg + end) / 2+1,end, num))return true;
	else return false;
}
void dps(int x){
	arr[x] = 1;
	full++;
	for each (long long y in graph[x])
	{
		if (arr[y] == 0)dps(y);
	}
	return;
}
int main(){
	long long n, m;
	long long ans=0;
	cin >> n>>m;
	for (int i = 0; i < n; i++){
		coun[i] = 0;
		arr[i] = 0;
	}
	for (int i = 0; i < m; i++){
		int a, b;
		cin >>a >> b;
		if (a == b){
			coun[a - 1]++;
			graph[a - 1].push_back(b - 1);
		}
		else{
			coun[a - 1]++;
			coun[b - 1]++;
			graph[a - 1].push_back(b - 1);
			graph[b - 1].push_back(a - 1);
		}
	}
	dps(0);
	if (full!=n){
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; i++){
		ans += coun[i]*(coun[i]-1) / 2;
	}

	cout << ans;
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <utility>
#include <algorithm>
#include <stdio.h>
#include <math.h>

using namespace std;
long long coun[1000005];
long long arr[1000005];
long long full = 0;
vector<long long> graph[1000005];
bool binSearch(long long beg, long long end, long long num){
	if (beg == end){
		if (coun[beg] == num)return true;
		else return false;
	}
	if (binSearch(beg, (beg + end) / 2, num))return true;
	else if (binSearch((beg + end) / 2+1,end, num))return true;
	else return false;
}
void dps(int x){
	arr[x] = 1;
	full++;
	for each (long long y in graph[x])
	{
		if (arr[y] == 0)dps(y);
	}
	return;
}
int main(){
	long long n, m;
	long long ans=0;
	cin >> n>>m;
	if (m == 1||n==1){
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; i++){
		coun[i] = 0;
		arr[i] = 0;
	}
		long long a, b;
	for (int i = 0; i < m; i++){
		cin >>a >> b;
		if (a == b){
			coun[a - 1]++;
			graph[a - 1].push_back(b - 1);
		}
		else{
			coun[a - 1]++;
			coun[b - 1]++;
			graph[a - 1].push_back(b - 1);
			graph[b - 1].push_back(a - 1);
		}
	}
	long long num = 0;
	for (int i = 0; i < n; i++){
		if (graph[i].size()>0)num++;
	}
	dps(a-1);
	if (full!=num){
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; i++){
		if(coun[i]!=0)ans += coun[i]*(coun[i]-1) / 2;
	}

	cout << ans;
	return 0;
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <deque>
#include <queue>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <float.h>
#include <limits>
#include <list>
#include <map>
#include <math.h>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <vector>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pi;
typedef pair<ll, ll> pl;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<pi> vp;
typedef vector<string> vs;
typedef set<int> si;
typedef map<int, int> mi;
typedef map<ll, ll> ml;

int n, m;
vi* al;

struct UnionFind
{
	vi data;
	UnionFind(int size)
		: data(size, -1)
	{
	}
	bool unionSet(int x, int y)
	{
		x = root(x);
		y = root(y);
		if (x != y)
		{
			if (data[y] < data[x])
				swap(x, y);
			data[x] += data[y];
			data[y] = x;
		}
		return x != y;
	}
	bool findSet(int x, int y)
	{
		return root(x) == root(y);
	}
	int root(int x)
	{
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x)
	{
		return -data[root(x)];
	}
};

int main()
{
	ios::sync_with_stdio(false);

	scanf("%d %d", &n, &m);

	al = new vi[n];

	UnionFind uf(n);
	int loops = 0;
	vb loop_vertexes(n);

	for (int i = 0; i < m; ++i)
	{
		int u, v;
		scanf("%d %d", &u, &v);
		--u;
		--v;
		if (u == v)
		{
			++loops;
			loop_vertexes[u] = true;
		}
		else
		{
			al[u].push_back(v);
			al[v].push_back(u);
			uf.unionSet(u, v);
		}
	}

	int disconnected = 0;
	for (int i = 0; i < n; ++i)
	{
		int size = uf.size(i);
		if (size == 1)
		{
			if (loop_vertexes[i])
			{
				cout << 0 << endl;
				return 0;
			}
			++disconnected;
		}
	}

	for (int i = 0; i < n; ++i)
	{
		int size = uf.size(i);
		if (size != 1 && size != n - disconnected)
		{
			cout << 0 << endl;
			return 0;
		}
	}

	ll res = 0;

	for (int i = 0; i < n; ++i)
	{
		for (int j = 0, size = al[i].size(); j < size; ++j)
		{
			int v = al[i][j];
			res += al[v].size() - 1;
		}
	}

	ll total_res = res / 2;

	if (loops)
		total_res += (ll)loops * (ll)(m - loops);
	if (loops > 1)
		total_res += (ll)loops * (ll)(loops - 1) / 2;

	cout << total_res << endl;

	return 0;
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <deque>
#include <queue>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <float.h>
#include <limits>
#include <list>
#include <map>
#include <math.h>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <vector>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pi;
typedef pair<ll, ll> pl;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<pi> vp;
typedef vector<string> vs;
typedef set<int> si;
typedef map<int, int> mi;
typedef map<ll, ll> ml;

int n, m;
vi* al;

struct UnionFind
{
	vi data;
	UnionFind(int size)
		: data(size, -1)
	{
	}
	bool unionSet(int x, int y)
	{
		x = root(x);
		y = root(y);
		if (x != y)
		{
			if (data[y] < data[x])
				swap(x, y);
			data[x] += data[y];
			data[y] = x;
		}
		return x != y;
	}
	bool findSet(int x, int y)
	{
		return root(x) == root(y);
	}
	int root(int x)
	{
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x)
	{
		return -data[root(x)];
	}
};

int main()
{
	ios::sync_with_stdio(false);

	scanf("%d %d", &n, &m);

	al = new vi[n];

	UnionFind uf(n);
	int loops = 0;

	for (int i = 0; i < m; ++i)
	{
		int u, v;
		scanf("%d %d", &u, &v);
		--u;
		--v;
		if (u == v)
		{
			++loops;
		}
		else
		{
			al[u].push_back(v);
			al[v].push_back(u);
			uf.unionSet(u, v);
		}
	}

	int size = uf.size(0);

	if (size != n)
	{
		cout << 0 << endl;
		return 0;
	}

	ll res = 0;

	for (int i = 0; i < n; ++i)
	{
		for (int j = 0, size = al[i].size(); j < size; ++j)
		{
			int v = al[i][j];
			res += al[v].size() - 1;
		}
	}

	ll total_res = res / 2;

	if (loops)
		total_res += (ll)loops * (ll)(m - loops);
	if (loops > 1)
		total_res += (ll)loops * (ll)(loops - 1) / 2;

	cout << total_res << endl;

	return 0;
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <deque>
#include <queue>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <float.h>
#include <limits>
#include <list>
#include <map>
#include <math.h>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <vector>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pi;
typedef pair<ll, ll> pl;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<pi> vp;
typedef vector<string> vs;
typedef set<int> si;
typedef map<int, int> mi;
typedef map<ll, ll> ml;

int n, m;
vi* al;

struct UnionFind
{
	vi data;
	UnionFind(int size)
		: data(size, -1)
	{
	}
	bool unionSet(int x, int y)
	{
		x = root(x);
		y = root(y);
		if (x != y)
		{
			if (data[y] < data[x])
				swap(x, y);
			data[x] += data[y];
			data[y] = x;
		}
		return x != y;
	}
	bool findSet(int x, int y)
	{
		return root(x) == root(y);
	}
	int root(int x)
	{
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x)
	{
		return -data[root(x)];
	}
};

int main()
{
	ios::sync_with_stdio(false);

	scanf("%d %d", &n, &m);

	al = new vi[n];

	UnionFind uf(n);

	for (int i = 0; i < m; ++i)
	{
		int u, v;
		scanf("%d %d", &u, &v);
		--u;
		--v;
		al[u].push_back(v);
		if (u != v)
		{
			al[v].push_back(u);
			uf.unionSet(u, v);
		}
	}

	int size = uf.size(0);

	if (size != n)
	{
		cout << 0 << endl;
		return 0;
	}

	int res = 0;

	for (int i = 0; i < n; ++i)
	{
		for (int j = 0, size = al[i].size(); j < size; ++j)
		{
			int v = al[i][j];
			res += al[v].size() - 1;
		}
	}

	cout << res / 2 << endl;

	return 0;
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <deque>
#include <queue>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <float.h>
#include <limits>
#include <list>
#include <map>
#include <math.h>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <vector>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pi;
typedef pair<ll, ll> pl;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<pi> vp;
typedef vector<string> vs;
typedef set<int> si;
typedef map<int, int> mi;
typedef map<ll, ll> ml;

int n, m;
vi* al;

struct UnionFind
{
	vi data;
	UnionFind(int size)
		: data(size, -1)
	{
	}
	bool unionSet(int x, int y)
	{
		x = root(x);
		y = root(y);
		if (x != y)
		{
			if (data[y] < data[x])
				swap(x, y);
			data[x] += data[y];
			data[y] = x;
		}
		return x != y;
	}
	bool findSet(int x, int y)
	{
		return root(x) == root(y);
	}
	int root(int x)
	{
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x)
	{
		return -data[root(x)];
	}
};

int main()
{
	ios::sync_with_stdio(false);

	scanf("%d %d", &n, &m);

	al = new vi[n];

	UnionFind uf(n);
	int loops = 0;

	for (int i = 0; i < m; ++i)
	{
		int u, v;
		scanf("%d %d", &u, &v);
		--u;
		--v;
		if (u == v)
		{
			++loops;
		}
		else
		{
			al[u].push_back(v);
			al[v].push_back(u);
			uf.unionSet(u, v);
		}
	}

	int disconnected = 0;
	for (int i = 0; i < n; ++i)
	{
		int size = uf.size(i);
		if (size == 1)
			++disconnected;
	}

	for (int i = 0; i < n; ++i)
	{
		int size = uf.size(i);
		if (size != 1 && size != n - disconnected)
		{
			cout << 0 << endl;
			return 0;
		}
	}

	ll res = 0;

	for (int i = 0; i < n; ++i)
	{
		for (int j = 0, size = al[i].size(); j < size; ++j)
		{
			int v = al[i][j];
			res += al[v].size() - 1;
		}
	}

	ll total_res = res / 2;

	if (loops)
		total_res += (ll)loops * (ll)(m - loops);
	if (loops > 1)
		total_res += (ll)loops * (ll)(loops - 1) / 2;

	cout << total_res << endl;

	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <bitset>		//UWAGA - w czasie kompilacji musi byc znany rozmiar wektora - nie mozna go zmienic
#include <cassert>
#include <iomanip>		//do setprecision
#include <ctime>
#include <complex>
using namespace std;

#define FOR(i,b,e) for(int i=(b);i<(e);++i)
#define FORQ(i,b,e) for(int i=(b);i<=(e);++i)
#define FORD(i,b,e) for(int i=(b)-1;i>=(e);--i)
#define REP(x, n) for(int x = 0; x < (n); ++x)

#define ST first
#define ND second
#define PB push_back
#define MP make_pair
#define LL long long
#define ULL unsigned LL
#define LD long double

const double pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342;

const int MR = 1e6 + 10;

vector < int > g[MR];

bool done[MR], hasLoop[MR];

// policz ile razy chadzales po krawedziach
int dfs( int nr )
{
    int res = 0;
    done[nr] = 1;
    REP( i, g[nr].size() )
        if (!done[g[nr][i]])
            res += 1 + dfs( g[nr][i] );
        else
            res++;

    return res;
}

int main()
{
    int n, m, ilep = 0;
    scanf( "%d%d", &n, &m );

    if (m < 2)
    {
        printf( "0\n" );
        return 0;
    }

    REP( i, m )
    {
        int u, v;
        scanf( "%d%d", &u, &v ); u--; v--;

        g[u].push_back( v );

        if (u == v)
        {
            hasLoop[u] = 1;
            ilep++;
        }
        else
            g[v].push_back( u );
    }

    REP( i, n )
    {
        if (!done[i])
        {
            int ile = dfs( i );
            if (ile && ile < 2 * m)
            {
                printf( "0\n" );
                return 0;
            }
        }
    }

    // wszystkie krawedzie sa w jednej skladowej
    // jedz po wierzcholkach - wybierz jedna krawedz przystajaca
    // druga krawedz to moze byc dowolna petla
    // lub krawedz przystajaca do sasiada
    LL res = 0;
    REP( i, n )REP( j, g[i].size() )
        res +=
        ilep // petle
        + g[g[i][j]].size() - 1 - hasLoop[g[i][j]]; // przystajace do sasiada, oprocz krawedzi do wierzcholka i oraz petli

    printf( "%lld\n", res / 2 );

    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <bitset>		//UWAGA - w czasie kompilacji musi byc znany rozmiar wektora - nie mozna go zmienic
#include <cassert>
#include <iomanip>		//do setprecision
#include <ctime>
#include <complex>
using namespace std;

#define FOR(i,b,e) for(int i=(b);i<(e);++i)
#define FORQ(i,b,e) for(int i=(b);i<=(e);++i)
#define FORD(i,b,e) for(int i=(b)-1;i>=(e);--i)
#define REP(x, n) for(int x = 0; x < (n); ++x)

#define ST first
#define ND second
#define PB push_back
#define MP make_pair
#define LL long long
#define ULL unsigned LL
#define LD long double

const double pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342;

const int MR = 1e6 + 10;

vector < int > g[MR];

bool done[MR], hasLoop[MR];

// policz ile razy chadzales po krawedziach
int dfs( int nr )
{
    int res = 0;
    done[nr] = 1;
    REP( i, g[nr].size() )
        if (!done[g[nr][i]])
            res += 1 + dfs( g[nr][i] );
        else if (g[nr][i] != nr)
            res++;
        else
            res += 2;

    return res;
}

int main()
{
    int n, m, ilep = 0;
    scanf( "%d%d", &n, &m );

    if (m < 2)
    {
        printf( "0\n" );
        return 0;
    }

    REP( i, m )
    {
        int u, v;
        scanf( "%d%d", &u, &v ); u--; v--;

        g[u].push_back( v );

        if (u == v)
        {
            hasLoop[u] = 1;
            ilep++;
        }
        else
            g[v].push_back( u );
    }

    REP( i, n )
    {
        if (!done[i])
        {
            int ile = dfs( i );
            if (ile && ile < 2 * m)
            {
                printf( "0\n" );
                return 0;
            }
        }
    }

    // wszystkie krawedzie sa w jednej skladowej
    // jedz po wierzcholkach - wybierz jedna krawedz przystajaca
    // druga krawedz to moze byc dowolna petla
    // lub krawedz przystajaca do sasiada
    LL res = 0;
    REP( i, n )REP( j, g[i].size() )
        res +=
        ilep // petle
        + g[g[i][j]].size() - 1 - hasLoop[g[i][j]]; // przystajace do sasiada, oprocz krawedzi do wierzcholka i oraz petli

    printf( "%lld\n", res / 2 );

    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <bitset>		//UWAGA - w czasie kompilacji musi byc znany rozmiar wektora - nie mozna go zmienic
#include <cassert>
#include <iomanip>		//do setprecision
#include <ctime>
#include <complex>
using namespace std;

#define FOR(i,b,e) for(int i=(b);i<(e);++i)
#define FORQ(i,b,e) for(int i=(b);i<=(e);++i)
#define FORD(i,b,e) for(int i=(b)-1;i>=(e);--i)
#define REP(x, n) for(int x = 0; x < (n); ++x)

#define ST first
#define ND second
#define PB push_back
#define MP make_pair
#define LL long long
#define ULL unsigned LL
#define LD long double

const double pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342;

const int MR = 1e6 + 10;

vector < int > g[MR];

bool done[MR], hasLoop[MR];

// policz ile razy chadzales po krawedziach
int dfs( int nr )
{
    int res = 0;
    done[nr] = 1;
    REP( i, g[nr].size() )
        if (!done[g[nr][i]])
            res += 2 + dfs( g[nr][i] );
        else if (g[nr][i] == nr)
            res += 2;

    return res;
}

int main()
{
    int n, m, ilep = 0;
    scanf( "%d%d", &n, &m );

    if (m < 2)
    {
        printf( "0\n" );
        return 0;
    }

    REP( i, m )
    {
        int u, v;
        scanf( "%d%d", &u, &v ); u--; v--;

        g[u].push_back( v );

        if (u == v)
        {
            hasLoop[u] = 1;
            ilep++;
        }
        else
            g[v].push_back( u );
    }

    REP( i, n )
    {
        if (!done[i])
        {
            int ile = dfs( i );
            if (ile && ile < 2 * m)
            {
                printf( "0\n" );
                return 0;
            }
        }
    }

    // wszystkie krawedzie sa w jednej skladowej
    // jedz po wierzcholkach - wybierz jedna krawedz przystajaca
    // druga krawedz to moze byc dowolna petla
    // lub krawedz przystajaca do sasiada
    LL res = 0;
    REP( i, n )REP( j, g[i].size() )
        res +=
        ilep // petle
        + g[g[i][j]].size() - 1 - hasLoop[g[i][j]]; // przystajace do sasiada, oprocz krawedzi do wierzcholka i oraz petli

    printf( "%lld\n", res / 2 );

    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <bitset>		//UWAGA - w czasie kompilacji musi byc znany rozmiar wektora - nie mozna go zmienic
#include <cassert>
#include <iomanip>		//do setprecision
#include <ctime>
#include <complex>
using namespace std;

#define FOR(i,b,e) for(int i=(b);i<(e);++i)
#define FORQ(i,b,e) for(int i=(b);i<=(e);++i)
#define FORD(i,b,e) for(int i=(b)-1;i>=(e);--i)
#define REP(x, n) for(int x = 0; x < (n); ++x)

#define ST first
#define ND second
#define PB push_back
#define MP make_pair
#define LL long long
#define ULL unsigned LL
#define LD long double

const double pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342;

const int MR = 1e6 + 10;

vector < int > g[MR];

bool done[MR], hasLoop[MR];

// policz ile razy chadzales po krawedziach
int dfs( int nr )
{
    int res = 0;
    done[nr] = 1;
    REP( i, g[nr].size() )
        if (!done[g[nr][i]])
            res += 1 + dfs( g[nr][i] );
        else if (g[nr][i] != nr)
            res++;
        else
            res += 2;

    return res;
}

int main()
{
    int n, m, ilep = 0;
    scanf( "%d%d", &n, &m );

    if (m < 2)
    {
        printf( "0\n" );
        return 0;
    }

    REP( i, m )
    {
        int u, v;
        scanf( "%d%d", &u, &v ); u--; v--;

        g[u].push_back( v );

        if (u == v)
        {
            hasLoop[u] = 1;
            ilep++;
        }
        else
            g[v].push_back( u );
    }

    REP( i, n )
    {
        if (!done[i])
        {
            int ile = dfs( i );
            if (ile && ile < 2 * m)
            {
                printf( "0\n" );
                return 0;
            }
        }
    }

    // wszystkie krawedzie sa w jednej skladowej
    // jedz po wierzcholkach - wybierz jedna krawedz przystajaca
    // druga krawedz to moze byc dowolna petla
    // lub krawedz przystajaca do sasiada
    LL res = 0;
    REP( i, n )REP( j, g[i].size() )
        if (g[i][j] != i)
            res += g[g[i][j]].size() - 1 - hasLoop[g[i][j]]; // dodaj krawedzie do sasiada, bez tej samej krawedzi i bez petli

    res /= 2;

    // dolicz jeszcze pary gdzie sa 2 petle
    res += ilep*(LL)( ilep - 1 ) / 2;

    // teraz kazda normalna krawedz laczymy z jedna petla
    res += ( m - ilep )*(LL)ilep;

    printf( "%lld\n", res );

    return 0;
}


#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <set>

using namespace std;

const int MAXN = 1e6 + 10;

int n, m, st;
vector < int > g[MAXN];
int s[MAXN];
bool used[MAXN], cy[MAXN];
long long c[MAXN];
long long cyE = 0;

void dfs(int v) {
    used[v] = true;
    for (int i = 0; i < g[v].size(); i++) {
        int w = g[v][i];
        if (used[w]) {
            continue;
        }
        dfs(w);
    }
}

void initC() {
    c[0] = 0;
    c[1] = 0;
    for (int i = 1; i <= m; i++) {
        c[i + 1] = c[i] + i;
    }
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++) {
        int ai, bi;
        scanf("%d %d", &ai, &bi);
		if (ai != bi) {
			g[ai].push_back(bi);
			s[ai]++;
			st = ai;
			g[bi].push_back(ai);
			s[bi]++;
		} else {
			cy[ai] = true;
			cyE++;
		}
    }

    dfs(st);

    for (int i = 1; i <= n; i++) {
        if ((s[i] > 0 || cy[i]) && !used[i]) {
            cout << 0 << endl;
            return 0;
        }
    }

    initC();

    long long ans = 0;
    for (int i = 1; i <= n; i++) {
        ans += c[s[i]];
    }

	ans += cyE * (m - cyE);
	ans += c[cyE];

    cout << ans << endl;

    return 0;
}


#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <set>

using namespace std;

const int MAXN = 1e6 + 10;

int n, m, st;
vector < int > g[MAXN];
int s[MAXN];
bool used[MAXN];
long long c[MAXN];

void dfs(int v) {
    used[v] = true;
    for (int i = 0; i < g[v].size(); i++) {
        int w = g[v][i];
        if (used[w]) {
            continue;
        }
        dfs(w);
    }
}

void initC() {
    c[0] = 0;
    c[1] = 0;
    for (int i = 1; i <= n; i++) {
        c[i + 1] = i * i - c[i];
    }
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++) {
        int ai, bi;
        scanf("%d %d", &ai, &bi);
        g[ai].push_back(bi);
        s[ai]++;
		if (ai != bi) {
			s[bi]++;
			g[bi].push_back(ai);
		}
        st = ai;
    }

    dfs(st);

    for (int i = 1; i <= n; i++) {
        if (s[i] > 0 && !used[i]) {
            cout << 0 << endl;
            return 0;
        }
    }

    initC();

    long long ans = 0;
    for (int i = 1; i <= n; i++) {
        ans += c[s[i]];
    }

    cout << ans << endl;

    return 0;
}


#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <set>

using namespace std;

const int MAXN = 1e6 + 10;

int n, m, st;
vector < int > g[MAXN];
int s[MAXN];
bool used[MAXN];
long long c[MAXN];

void dfs(int v) {
    used[v] = true;
    for (int i = 0; i < g[v].size(); i++) {
        int w = g[v][i];
        if (used[w]) {
            continue;
        }
        dfs(w);
    }
}

void initC() {
    c[0] = 0;
    c[1] = 0;
    for (int i = 1; i <= n; i++) {
        c[i + 1] = i * i - c[i];
    }
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++) {
        int ai, bi;
        scanf("%d %d", &ai, &bi);
        g[ai].push_back(bi);
        g[bi].push_back(ai);
        s[ai]++;
        s[bi]++;
        st = ai;
    }

    dfs(st);

    for (int i = 1; i <= n; i++) {
        if (s[i] > 0 && !used[i]) {
            cout << 0 << endl;
            return 0;
        }
    }

    initC();

    long long ans = 0;
    for (int i = 1; i <= n; i++) {
        ans += c[s[i]];
    }

    cout << ans << endl;

    return 0;
}


# include <iostream>
# include <sstream>
# include <cstdio>
# include <cstdlib>
# include <algorithm>
# include <string>
# include <cstring>
# include <cmath>
# include <stack>
# include <queue>
# include <vector>
# include <list>
# include <map>
# include <set>
# include <deque>
# include <iterator>
# include <functional>
# include <bitset>
# include <climits>
# include <ctime>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define odd(x) (x&1)
typedef long long ll;
typedef long double ld;
const ll oo = 2 * 1000 * 1000 * 1000;
const int _cnt = 1000 * 1000;
const int _p = 1000 * 1000 * 1000 + 7;
ll o(ll x) { return x%_p; }
int gcd(int a, int b) { return b ? gcd(b, a%b) : a; }
int lcm(int a, int b) { return a / gcd(a, b)*b; }
using namespace std;

void file_put() {
	freopen("filename.in", "r", stdin);
	freopen("filename.out", "w", stdout);
}

int home[1000005], degree[1000005], total = 0, ans = 0;
int x, y, n, m, p, q;

int _find(int k) {
	if (k == home[k]) return k;
	return home[k] = _find(home[k]);
}

int main() {
	//file_put();

	scanf("%d%d", &n, &m);
	if (m < n - 1) {
		printf("0\n");
		return 0;
	}
	for (int i = 1; i <= n; i++) home[i] = i;
	total = n;
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		if (x!=y) degree[x]++;
		if (x!=y) degree[y]++;
		p = _find(x);
		q = _find(y);
		if (p == q) continue;
		home[p] = q;
		total--;
	}
	if (total > 1) {
		printf("0\n");
		return 0;
	}
	for (int i = 1; i <= n; i++) ans += (degree[i] == 1);
	printf("%I64d\n", (ll)ans*(ans - 1) / 2);

	return 0;
}


# include <iostream>
# include <sstream>
# include <cstdio>
# include <cstdlib>
# include <algorithm>
# include <string>
# include <cstring>
# include <cmath>
# include <stack>
# include <queue>
# include <vector>
# include <list>
# include <map>
# include <set>
# include <deque>
# include <iterator>
# include <functional>
# include <bitset>
# include <climits>
# include <ctime>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define odd(x) (x&1)
typedef long long ll;
typedef long double ld;
const ll oo = 2 * 1000 * 1000 * 1000;
const int _cnt = 1000 * 1000;
const int _p = 1000 * 1000 * 1000 + 7;
ll o(ll x) { return x%_p; }
int gcd(int a, int b) { return b ? gcd(b, a%b) : a; }
int lcm(int a, int b) { return a / gcd(a, b)*b; }
using namespace std;

void file_put() {
	freopen("filename.in", "r", stdin);
	freopen("filename.out", "w", stdout);
}

int home[1000005], degree[1000005], total = 0, cnt = 0, lone = 0;
int x, y, n, m, p, q;
ll ans = 0;
bool mark[1000005];

int _find(int k) {
	if (k == home[k]) return k;
	return home[k] = _find(home[k]);
}

int main() {
	//file_put();

	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) home[i] = i;
	memset(mark, 0, sizeof(mark));
	total = n;
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		mark[x] = mark[y] = 1;
		if (x == y) cnt++;
		if (x != y) {
			degree[x]++;
			degree[y]++;
		}
		p = _find(x);
		q = _find(y);
		if (p == q) continue;
		home[p] = q;
		total--;
	}
	for (int i = 1; i <= n; i++) lone += (mark[i] == 0);
	if (total - lone != 1) {
		printf("0\n");
		return 0;
	}
	ans = 0;
	for (int i = 1; i <= n; i++) ans += (ll)degree[i] * (degree[i] - 1) / 2;
	ans += (ll)cnt*(2 * m - cnt - 1) / 2;
	printf("%I64d\n", ans);

	return 0;
}


# include <iostream>
# include <sstream>
# include <cstdio>
# include <cstdlib>
# include <algorithm>
# include <string>
# include <cstring>
# include <cmath>
# include <stack>
# include <queue>
# include <vector>
# include <list>
# include <map>
# include <set>
# include <deque>
# include <iterator>
# include <functional>
# include <bitset>
# include <climits>
# include <ctime>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define odd(x) (x&1)
typedef long long ll;
typedef long double ld;
const ll oo = 2 * 1000 * 1000 * 1000;
const int _cnt = 1000 * 1000;
const int _p = 1000 * 1000 * 1000 + 7;
ll o(ll x) { return x%_p; }
int gcd(int a, int b) { return b ? gcd(b, a%b) : a; }
int lcm(int a, int b) { return a / gcd(a, b)*b; }
using namespace std;

void file_put() {
	freopen("filename.in", "r", stdin);
	freopen("filename.out", "w", stdout);
}

int home[1000005], degree[1000005], total = 0, cnt = 0, lone = 0;
int x, y, n, m, p, q;
ll ans = 0;
bool mark[1000005];

int _find(int k) {
	if (k == home[k]) return k;
	return home[k] = _find(home[k]);
}

int main() {
	//file_put();

	scanf("%d%d", &n, &m);
	if (m < n - 1) {
		printf("0\n");
		return 0;
	}
	for (int i = 1; i <= n; i++) home[i] = i;
	memset(mark, 0, sizeof(mark));
	total = n;
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		mark[x] = mark[y] = 1;
		if (x == y) cnt++;
		if (x != y) {
			degree[x]++;
			degree[y]++;
		}
		p = _find(x);
		q = _find(y);
		if (p == q) continue;
		home[p] = q;
		total--;
	}
	for (int i = 1; i <= n; i++) lone += (mark[i] == 0);
	if (total - lone != 1) {
		printf("0\n");
		return 0;
	}
	ans = 0;
	for (int i = 1; i <= n; i++) ans += (ll)degree[i] * (degree[i] - 1) / 2;
	ans += (ll)cnt*(2 * m - cnt - 1) / 2;
	printf("%I64d\n", ans);

	return 0;
}


# include <iostream>
# include <sstream>
# include <cstdio>
# include <cstdlib>
# include <algorithm>
# include <string>
# include <cstring>
# include <cmath>
# include <stack>
# include <queue>
# include <vector>
# include <list>
# include <map>
# include <set>
# include <deque>
# include <iterator>
# include <functional>
# include <bitset>
# include <climits>
# include <ctime>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define odd(x) (x&1)
typedef long long ll;
typedef long double ld;
const ll oo = 2 * 1000 * 1000 * 1000;
const int _cnt = 1000 * 1000;
const int _p = 1000 * 1000 * 1000 + 7;
ll o(ll x) { return x%_p; }
int gcd(int a, int b) { return b ? gcd(b, a%b) : a; }
int lcm(int a, int b) { return a / gcd(a, b)*b; }
using namespace std;

void file_put() {
	freopen("filename.in", "r", stdin);
	freopen("filename.out", "w", stdout);
}

int home[1000005], degree[1000005], total = 0, cnt = 0;
int x, y, n, m, p, q;
ll ans = 0;

int _find(int k) {
	if (k == home[k]) return k;
	return home[k] = _find(home[k]);
}

int main() {
	//file_put();

	scanf("%d%d", &n, &m);
	if (m < n - 1) {
		printf("0\n");
		return 0;
	}
	for (int i = 1; i <= n; i++) home[i] = i;
	total = n;
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		if (x == y) cnt++;
		if (x != y) {
			degree[x]++;
			degree[y]++;
		}
		p = _find(x);
		q = _find(y);
		if (p == q) continue;
		home[p] = q;
		total--;
	}
	if (total > 1) {
		printf("0\n");
		return 0;
	}
	ans = 0;
	for (int i = 1; i <= n; i++) ans += (ll)degree[i] * (degree[i] - 1) / 2;
	ans += (ll)cnt*(2 * m - cnt - 1) / 2;
	printf("%I64d\n", ans);

	return 0;
}


# include <iostream>
# include <sstream>
# include <cstdio>
# include <cstdlib>
# include <algorithm>
# include <string>
# include <cstring>
# include <cmath>
# include <stack>
# include <queue>
# include <vector>
# include <list>
# include <map>
# include <set>
# include <deque>
# include <iterator>
# include <functional>
# include <bitset>
# include <climits>
# include <ctime>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define odd(x) (x&1)
typedef long long ll;
typedef long double ld;
const ll oo = 2 * 1000 * 1000 * 1000;
const int _cnt = 1000 * 1000;
const int _p = 1000 * 1000 * 1000 + 7;
ll o(ll x) { return x%_p; }
int gcd(int a, int b) { return b ? gcd(b, a%b) : a; }
int lcm(int a, int b) { return a / gcd(a, b)*b; }
using namespace std;

void file_put() {
	freopen("filename.in", "r", stdin);
	freopen("filename.out", "w", stdout);
}

int home[1000005], degree[1000005], total = 0, mark[1000005];
int x, y, n, m, p, q;
ll ans = 0;

int _find(int k) {
	if (k == home[k]) return k;
	return home[k] = _find(home[k]);
}

int main() {
	//file_put();

	scanf("%d%d", &n, &m);
	if (m < n - 1) {
		printf("0\n");
		return 0;
	}
	for (int i = 1; i <= n; i++) home[i] = i;
	total = n;
	memset(mark, 0, sizeof(mark));
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		if (x == y) mark[x] = 1;
		if (x != y) {
			degree[x]++;
			degree[y]++;
		}
		p = _find(x);
		q = _find(y);
		if (p == q) continue;
		home[p] = q;
		total--;
	}
	if (total > 1) {
		printf("0\n");
		return 0;
	}
	ans = 0;
	for (int i = 1; i <= n; i++) ans += (ll)degree[i] * (degree[i] + 2 * mark[i] - 1) / 2;
	printf("%I64d\n", ans);

	return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<cstdlib>
#include<vector>
#include<set>
#include<queue>
#include<cstring>
#include<string.h>
#include<algorithm>
typedef long long ll;
typedef unsigned long long LL;
using namespace std;
const int N=1000000+100;
int m,n;
int flag[N];
int head[N];
int vis[N];
ll a[N],b[N];
int cnt=0;
void init(){
    memset(vis,0,sizeof(vis));
    cnt=0;
    memset(head,-1,sizeof(head));
}
struct node{
    int to,next;
}edge[N*2+100];
void add(int u,int v){
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void DFS(int x){
    vis[x]=1;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(vis[v]==0){
            DFS(v);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    init();
    ll t1=0;
    ll t2=0;
    int u,v;
    memset(a,0,sizeof(a));
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        b[u]=b[v]=1;
        if(u!=v){add(u,v);add(v,u);t1++;a[u]++;a[v]++;}
        else
            t2++;
    }
    DFS(u);
    for(int i=1;i<=n;i++){
        if(vis[i]==0&&b[i]){
            cout<<0<<endl;
            return 0;
        }
    }
    ll ans=0;
    ans=ans+t1*t2;
    ans=ans+(t2*(t2-1))/2;
    for(int i=1;i<=n;i++)
        ans=ans+(a[i]*(a[i]-1))/2;
    printf("%I64d\n",ans);
}


// rc.cpp : Defines the entry point for the console application.
//

#include <math.h>

#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <string>
#include <bitset>
#include <cstdio>
#include <limits>
#include <vector>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <functional>
#include <iomanip>

using namespace std;

#define PI 3.14159265358979323846
#define EPS 1.E-8

typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long long uint64;
typedef long long sint64;

vector<uint> gr[1000000];
bool vs[1000000];

uint64 qe;
uint c;

void dfs(uint cv)
{
    uint sz = gr[cv].size();
    qe += (uint64)sz * (sz - 1) / 2;
    ++c;

    for (uint i = 0; i < sz; ++i) {
        uint nx = gr[cv][i];
        if (!vs[nx]) {
            vs[nx] = true;
            dfs(nx);
        }
    }
}

uint va[1000000];

int main(int argc, char* argv[])
{
    ios_base::sync_with_stdio(false);

    uint n, m;
    scanf("%d%d", &n, &m);

    uint64 se = 0;
    uint sse = -1;
    for (uint i = 0; i < m; ++i) {

        uint u, v;
        scanf("%d%d", &u, &v);
        --u, --v;

        va[u] = 1;
        va[v] = 1;

        if (u < sse)
            sse = u;
        if (v < sse)
            sse = v;

        if (u != v) {
            gr[u].push_back(v);
            gr[v].push_back(u);
        }
        else
            ++se;
    }

    vs[sse] = true;
    dfs(sse);

    uint zc = accumulate(va, va + n, 0);

    if (c == zc) {
        uint64 r = se * (se - 1) / 2;
        r += se * (m - se);
        r += qe;
        printf("%I64d\n", r);
    }
    else
        printf("0\n");

    return 0;
}


// rc.cpp : Defines the entry point for the console application.
//

#include <math.h>

#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <string>
#include <bitset>
#include <cstdio>
#include <limits>
#include <vector>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <functional>
#include <iomanip>

using namespace std;

#define PI 3.14159265358979323846
#define EPS 1.E-8

typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long long uint64;
typedef long long sint64;

vector<uint> gr[1000000];
bool vs[1000000];

uint64 qe;

void dfs(uint cv)
{
    uint sz = gr[cv].size();
    qe += (uint64)sz * (sz - 1) / 2;

    for (uint i = 0; i < sz; ++i) {
        uint nx = gr[cv][i];
        if (!vs[nx]) {
            vs[nx] = true;
            dfs(nx);
        }
    }
}

int main(int argc, char* argv[])
{
    ios_base::sync_with_stdio(false);

    uint n, m;
    cin >> n >> m;

    uint64 se = 0;
    for (uint i = 0; i < m; ++i) {

        uint u, v;
        cin >> u >> v;

        if (u != v) {
            --u, --v;
            gr[u].push_back(v);
            gr[v].push_back(u);
        }
        else
            ++se;
    }

    vs[0] = true;
    dfs(0);

    bool c = true;
    for (uint i = 0; i < n; ++i) {
        if (!vs[i]) {
            c = false;
            break;
        }
    }

    if (c) {
        uint64 r = se * (se - 1) / 2;
        r += se * (m - se);
        r += qe;
        cout << r << endl;
    }
    else
        cout << "0\n";

    return 0;
}


// rc.cpp : Defines the entry point for the console application.
//

#include <math.h>

#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <string>
#include <bitset>
#include <cstdio>
#include <limits>
#include <vector>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <functional>
#include <iomanip>

using namespace std;

#define PI 3.14159265358979323846
#define EPS 1.E-8

typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long long uint64;
typedef long long sint64;

vector<uint> gr[1000000];
bool vs[1000000];

uint64 qe;

void dfs(uint cv)
{
    uint sz = gr[cv].size();
    qe += (uint64)sz * (sz - 1) / 2;

    for (uint i = 0; i < sz; ++i) {
        uint nx = gr[cv][i];
        if (!vs[nx]) {
            vs[nx] = true;
            dfs(nx);
        }
    }
}

uint va[1000000];

int main(int argc, char* argv[])
{
    ios_base::sync_with_stdio(false);

    uint n, m;
    cin >> n >> m;

    uint64 se = 0;
    uint sse = -1;
    for (uint i = 0; i < m; ++i) {

        uint u, v;
        cin >> u >> v;
        --u, --v;

        va[u] = 1;
        va[v] = 1;

        if (u < sse)
            sse = u;
        if (v < sse)
            sse = v;

        if (u != v) {
            gr[u].push_back(v);
            gr[v].push_back(u);
        }
        else
            ++se;
    }

    vs[sse] = true;
    dfs(sse);

    uint zc = accumulate(va, va + n, 0),
         c = 0;
    for (uint i = 0; i < n; ++i) {
        if (vs[i])
            ++c;
    }

    if (c == zc) {
        uint64 r = se * (se - 1) / 2;
        r += se * (m - se);
        r += qe;
        cout << r << endl;
    }
    else
        cout << "0\n";

    return 0;
}


use std::fmt::Debug;
use std::io::BufRead;
use std::io::{stdin, Read};
use std::ops::{Add, Sub};
use std::str::FromStr;

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<std::cmp::Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> std::cmp::Ordering {
        other.0.cmp(&self.0)
    }
}

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();

    token.parse().ok().expect("failed to parse token")
}

macro_rules! read {
    (($($t:tt),*)) => {
        ( $(read!($t)),* )
    };
    ([[$t:tt; $len1:expr]; $len2:expr]) => {
        (0..$len2).map(|_| read!([$t; $len1])).collect::<Vec<_>>()
    };

    ([$t:tt; $len:expr]) => {
        (0..$len).map(|_| read!($t)).collect::<Vec<_>>()
    };

    (chars) => {
        read!(String).chars().collect::<Vec<char>>()
    };

    (usize1) => {
        read!(usize) - 1
    };

    ($t:ty) => {{
        let stdin = stdin();
        let stdin = stdin.lock();
        let token: String = stdin
            .bytes()
            .map(|c| c.unwrap() as char)
            .skip_while(|c| c.is_whitespace())
            .take_while(|c| !c.is_whitespace())
            .collect();

        token.parse::<$t>().unwrap()
    }};
}

macro_rules! input {
    (mut $name:ident: $t:tt, $($r:tt)*) => {
        let mut $name = read!($t);
        input!($($r)*);
    };

    (mut $name:ident: $t:tt) => {
        let mut $name = read!($t);
    };

    ($name:ident: $t:tt, $($r:tt)*) => {
        let $name = read!($t);
        input!($($r)*);
    };

    ($name:ident: $t:tt) => {
        let $name = read!($t);
    };
}

trait VecExt {
    fn cumulation(&self) -> Vec<i64>;
    fn cumulation_query(&self, a: &usize, b: &usize) -> i64;
}

impl VecExt for Vec<i64> {
    fn cumulation(&self) -> Vec<i64> {
        let mut vec = vec![0; self.len() + 1];
        for i in 0..self.len() {
            vec[i + 1] = self[i] + vec[i];
        }
        return vec;
    }

    fn cumulation_query(&self, left: &usize, right: &usize) -> i64 {
        return self[*right] - self[*left];
    }
}

trait SliceExt<T> {
    fn lower_bound(&self, x: &T) -> usize;
    fn upper_bound(&self, x: &T) -> usize;
}

impl<T: Ord> SliceExt<T> for [T] {
    fn lower_bound(&self, x: &T) -> usize {
        let mut ng = -1;
        let mut ok = self.len() as i64;

        while (ok - ng).abs() > 1 {
            let mid = (ok + ng) / 2;
            if self[mid as usize] >= *x {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        return ok as usize;
    }

    fn upper_bound(&self, x: &T) -> usize {
        let mut ng = -1;
        let mut ok = self.len() as i64;
        while (ok - ng).abs() > 1 {
            let mid = (ok + ng) / 2;
            if self[mid as usize] > *x {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        return ok as usize;
    }
}

fn main() {
    input!(n: usize, a: [(usize, usize, i64); n]);
    use std::cmp::max;

    let mut dp = vec![vec![-1; 2010]; n + 10];
    dp[0][0] = 0;
    for i in 0..n {
        for j in 0..2010 {
            if dp[i][j] != -1 {
            if j + a[i].0 < a[i].1 {
                dp[i + 1][j + a[i].0] = max(dp[i + 1][j + a[i].0], dp[i][j] + a[i].2);
            }

            dp[i + 1][j] = max(dp[i + 1][j], dp[i][j]);
            }
        }
    }

    let (mut idx, ans) = dp[n]
        .iter()
        .enumerate()
        .filter(|(_, x)| **x != -1)
        .max_by(|(a, b), (c, d)| b.cmp(d))
        .unwrap();

    let mut path = vec![];
    let mut i = n;
    while idx > 0 && n > 0 {
        if dp[i][idx] == dp[i - 1][idx] {
            i -= 1;
        } else if dp[i][idx] == dp[i - 1][idx - a[i - 1].0] + a[i - 1].2 {
            idx -= a[i - 1].0;
            path.push(i);
        }
    }

    println!("{}", ans);
    for x in path.iter().rev() {
        print!("{} ", x);
    }

    println!();
}


use std::fmt::Debug;
use std::io::BufRead;
use std::io::{stdin, Read};
use std::ops::{Add, Sub};
use std::str::FromStr;

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<std::cmp::Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> std::cmp::Ordering {
        other.0.cmp(&self.0)
    }
}

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();

    token.parse().ok().expect("failed to parse token")
}

macro_rules! read {
    (($($t:tt),*)) => {
        ( $(read!($t)),* )
    };
    ([[$t:tt; $len1:expr]; $len2:expr]) => {
        (0..$len2).map(|_| read!([$t; $len1])).collect::<Vec<_>>()
    };

    ([$t:tt; $len:expr]) => {
        (0..$len).map(|_| read!($t)).collect::<Vec<_>>()
    };

    (chars) => {
        read!(String).chars().collect::<Vec<char>>()
    };

    (usize1) => {
        read!(usize) - 1
    };

    ($t:ty) => {{
        let stdin = stdin();
        let stdin = stdin.lock();
        let token: String = stdin
            .bytes()
            .map(|c| c.unwrap() as char)
            .skip_while(|c| c.is_whitespace())
            .take_while(|c| !c.is_whitespace())
            .collect();

        token.parse::<$t>().unwrap()
    }};
}

macro_rules! input {
    (mut $name:ident: $t:tt, $($r:tt)*) => {
        let mut $name = read!($t);
        input!($($r)*);
    };

    (mut $name:ident: $t:tt) => {
        let mut $name = read!($t);
    };

    ($name:ident: $t:tt, $($r:tt)*) => {
        let $name = read!($t);
        input!($($r)*);
    };

    ($name:ident: $t:tt) => {
        let $name = read!($t);
    };
}

trait VecExt {
    fn cumulation(&self) -> Vec<i64>;
    fn cumulation_query(&self, a: &usize, b: &usize) -> i64;
}

impl VecExt for Vec<i64> {
    fn cumulation(&self) -> Vec<i64> {
        let mut vec = vec![0; self.len() + 1];
        for i in 0..self.len() {
            vec[i + 1] = self[i] + vec[i];
        }
        return vec;
    }

    fn cumulation_query(&self, left: &usize, right: &usize) -> i64 {
        return self[*right] - self[*left];
    }
}

trait SliceExt<T> {
    fn lower_bound(&self, x: &T) -> usize;
    fn upper_bound(&self, x: &T) -> usize;
}

impl<T: Ord> SliceExt<T> for [T] {
    fn lower_bound(&self, x: &T) -> usize {
        let mut ng = -1;
        let mut ok = self.len() as i64;

        while (ok - ng).abs() > 1 {
            let mid = (ok + ng) / 2;
            if self[mid as usize] >= *x {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        return ok as usize;
    }

    fn upper_bound(&self, x: &T) -> usize {
        let mut ng = -1;
        let mut ok = self.len() as i64;
        while (ok - ng).abs() > 1 {
            let mid = (ok + ng) / 2;
            if self[mid as usize] > *x {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        return ok as usize;
    }
}

fn main() {
    input!(n: usize, vec: [(usize, usize, i64); n]);
    use std::cmp::max;
    let mut a = vec![];
    for (i, x) in vec.into_iter().enumerate() {
        a.push((x.0, x.1, x.2, i));
    }
    a.sort_by(|(_, a, _, _), (_, b, _, _)| a.cmp(b));
    let mut dp = vec![vec![-1; 2010]; n + 10];
    dp[0][0] = 0;
    for i in 0..n {
        for j in 0..2010 {
            if dp[i][j] != -1 {
                dp[i + 1][j] = max(dp[i + 1][j], dp[i][j]);

                if j + a[i].0 < a[i].1 {
                    dp[i + 1][j + a[i].0] = max(dp[i + 1][j + a[i].0], dp[i][j] + a[i].2);
                }
            }
        }
    }

    let (mut idx, ans) = dp[n]
        .iter()
        .enumerate()
        .max_by(|(a, b), (c, d)| b.cmp(d))
        .unwrap();

    let mut path = vec![];
    let mut i = n;
    while idx > 0 && n > 0 {
        if idx >= a[i - 1].0 && dp[i][idx] == dp[i - 1][idx - a[i - 1].0] + a[i - 1].2 {
            idx -= a[i - 1].0;
            path.push(a[i - 1].3 + 1);
            i -= 1;
        } else {
            i -= 1;
        }
    }

    println!("{}", ans);
    println!("{}", path.len());
    for x in path.iter().rev() {
        print!("{} ", x);
    }

    println!();
}


use std::fmt::Debug;
use std::io::BufRead;
use std::io::{stdin, Read};
use std::ops::{Add, Sub};
use std::str::FromStr;

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<std::cmp::Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> std::cmp::Ordering {
        other.0.cmp(&self.0)
    }
}

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();

    token.parse().ok().expect("failed to parse token")
}

macro_rules! read {
    (($($t:tt),*)) => {
        ( $(read!($t)),* )
    };
    ([[$t:tt; $len1:expr]; $len2:expr]) => {
        (0..$len2).map(|_| read!([$t; $len1])).collect::<Vec<_>>()
    };

    ([$t:tt; $len:expr]) => {
        (0..$len).map(|_| read!($t)).collect::<Vec<_>>()
    };

    (chars) => {
        read!(String).chars().collect::<Vec<char>>()
    };

    (usize1) => {
        read!(usize) - 1
    };

    ($t:ty) => {{
        let stdin = stdin();
        let stdin = stdin.lock();
        let token: String = stdin
            .bytes()
            .map(|c| c.unwrap() as char)
            .skip_while(|c| c.is_whitespace())
            .take_while(|c| !c.is_whitespace())
            .collect();

        token.parse::<$t>().unwrap()
    }};
}

macro_rules! input {
    (mut $name:ident: $t:tt, $($r:tt)*) => {
        let mut $name = read!($t);
        input!($($r)*);
    };

    (mut $name:ident: $t:tt) => {
        let mut $name = read!($t);
    };

    ($name:ident: $t:tt, $($r:tt)*) => {
        let $name = read!($t);
        input!($($r)*);
    };

    ($name:ident: $t:tt) => {
        let $name = read!($t);
    };
}

trait VecExt {
    fn cumulation(&self) -> Vec<i64>;
    fn cumulation_query(&self, a: &usize, b: &usize) -> i64;
}

impl VecExt for Vec<i64> {
    fn cumulation(&self) -> Vec<i64> {
        let mut vec = vec![0; self.len() + 1];
        for i in 0..self.len() {
            vec[i + 1] = self[i] + vec[i];
        }
        return vec;
    }

    fn cumulation_query(&self, left: &usize, right: &usize) -> i64 {
        return self[*right] - self[*left];
    }
}

trait SliceExt<T> {
    fn lower_bound(&self, x: &T) -> usize;
    fn upper_bound(&self, x: &T) -> usize;
}

impl<T: Ord> SliceExt<T> for [T] {
    fn lower_bound(&self, x: &T) -> usize {
        let mut ng = -1;
        let mut ok = self.len() as i64;

        while (ok - ng).abs() > 1 {
            let mid = (ok + ng) / 2;
            if self[mid as usize] >= *x {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        return ok as usize;
    }

    fn upper_bound(&self, x: &T) -> usize {
        let mut ng = -1;
        let mut ok = self.len() as i64;
        while (ok - ng).abs() > 1 {
            let mid = (ok + ng) / 2;
            if self[mid as usize] > *x {
                ok = mid;
            } else {
                ng = mid;
            }
        }
        return ok as usize;
    }
}

fn main() {
    input!(n: usize, a: [(usize, usize, i64); n]);
    use std::cmp::max;

    let mut dp = vec![vec![-1; 2010]; n + 10];
    dp[0][0] = 0;
    for i in 0..n {
        for j in 0..2010 {
            if dp[i][j] != -1 {
            if j + a[i].0 < a[i].1 {
                dp[i + 1][j + a[i].0] = max(dp[i + 1][j + a[i].0], dp[i][j] + a[i].2);
            }

            dp[i + 1][j] = max(dp[i + 1][j], dp[i][j]);
            }
        }
    }

    let (mut idx, ans) = dp[n]
        .iter()
        .enumerate()
        .filter(|(_, x)| **x != -1)
        .max_by(|(a, b), (c, d)| b.cmp(d))
        .unwrap();

    let mut path = vec![];
    let mut i = n;
    while idx > 0 && n > 0 {
        if dp[i][idx] == dp[i - 1][idx] {
            i -= 1;
        } else if dp[i][idx] == dp[i - 1][idx - a[i - 1].0] + a[i - 1].2 {
            idx -= a[i - 1].0;
            path.push(i);
        }
    }

    println!("{}", ans);
    println!("{}", path.len());
    for x in path.iter().rev() {
        print!("{} ", x);
    }

    println!();
}


package main

import (
	"fmt"
	"sort"
)

type item struct {
	t, d, p, idx int
}

type byD []item

func (s byD) Len() int           { return len(s) }
func (s byD) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s byD) Less(i, j int) bool { return s[i].d < s[j].d }

const maxD = 2000

func main() {
	var n int
	fmt.Scan(&n)
	items := make([]item, n)
	for i := range items {
		fmt.Scan(&items[i].t, &items[i].d, &items[i].p)
		items[i].idx = i + 1
	}
	sort.Sort(byD(items))

	value := make([][]int, n+1)
	for i := range value {
		value[i] = make([]int, maxD+1)
		for j := range value[i] {
			value[i][j] = -1
		}
	}
	value[0][0] = 0
	take := make([][]int, n+1)
	for i := range take {
		take[i] = make([]int, maxD+1)
	}

	bestT := 0
	for i, it := range items {
		for t := maxD - 1; t >= 0; t-- {
			value[i+1][t] = value[i][t]
			take[i+1][t] = take[i][t]
			if t < it.t || t >= it.d {
				continue
			}
			cur := value[i][t-it.t]
			if cur == -1 {
				continue
			}
			cur += it.p
			if value[i+1][t] < cur {
				value[i+1][t] = cur
				take[i+1][t] = i
				if value[i][bestT] < cur {
					bestT = t
				}
			}
		}
	}

	fmt.Println(value[n][bestT])
	var taken []int
	for t, s := bestT, n; t > 0; {
		it := items[take[s][t]]
		s = take[s][t] - 1
		taken = append(taken, it.idx)
		t -= it.t
	}
	fmt.Println(len(taken))
	for i := len(taken) - 1; i >= 0; i-- {
		if i == 0 {
			fmt.Println(taken[i])
		} else {
			fmt.Print(taken[i], " ")
		}
	}
}


package main

import (
	"fmt"
	"sort"
)

type item struct {
	t, d, p, idx int
}

type byD []item

func (s byD) Len() int           { return len(s) }
func (s byD) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s byD) Less(i, j int) bool { return s[i].d < s[j].d }

const maxD = 2000

func main() {
	var n int
	fmt.Scan(&n)
	items := make([]item, n)
	for i := range items {
		fmt.Scan(&items[i].t, &items[i].d, &items[i].p)
		items[i].idx = i + 1
	}
	sort.Sort(byD(items))

	value := make([][]int, n+1)
	for i := range value {
		value[i] = make([]int, maxD+1)
	}
	take := make([][]int, n+1)
	for i := range take {
		take[i] = make([]int, maxD+1)
	}
	bestT := 0
	for i, it := range items {
		for t := it.d - 1; t >= it.t; t-- {
			value[i+1][t] = value[i][t]
			take[i+1][t] = take[i][t]
			if cur := value[i][t-it.t] + it.p; value[i+1][t] < cur {
				value[i+1][t] = cur
				take[i+1][t] = i
				if value[i+1][bestT] < cur {
					bestT = t
				}
			}
		}
	}

	fmt.Println(value[n][bestT])
	var taken []int
	for t, s := bestT, n; t > 0 && s > 0; s-- {
		it := items[take[s][t]]
		if len(taken) > 0 && it.idx == taken[len(taken)-1] {
			continue
		}
		taken = append(taken, it.idx)
		t -= it.t
	}
	fmt.Println(len(taken))
	for i := len(taken) - 1; i >= 0; i-- {
		if i == 0 {
			fmt.Println(taken[i])
		} else {
			fmt.Print(taken[i], " ")
		}
	}
}


package main

import (
	"fmt"
	"sort"
)

type item struct {
	t, d, p, idx int
}

type byD []item

func (s byD) Len() int           { return len(s) }
func (s byD) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s byD) Less(i, j int) bool { return s[i].d < s[j].d }

const maxD = 2000

func main() {
	var n int
	fmt.Scan(&n)
	items := make([]item, n)
	for i := range items {
		fmt.Scan(&items[i].t, &items[i].d, &items[i].p)
		items[i].idx = i + 1
	}
	sort.Sort(byD(items))

	value := make([][]int, n+1)
	for i := range value {
		value[i] = make([]int, maxD+1)
		for j := range value[i] {
			value[i][j] = -1
		}
	}
	value[0][0] = 0
	take := make([][]int, n+1)
	for i := range take {
		take[i] = make([]int, maxD+1)
	}

	bestT := 0
	for i, it := range items {
		for t := maxD - 1; t >= 0; t-- {
			value[i+1][t] = value[i][t]
			take[i+1][t] = take[i][t]
			if t < it.t || t >= it.d {
				continue
			}
			cur := value[i][t-it.t]
			if cur == -1 {
				continue
			}
			cur += it.p
			if value[i+1][t] < cur {
				value[i+1][t] = cur
				take[i+1][t] = i
				if value[i][bestT] < cur {
					bestT = t
				}
			}
		}
	}

	fmt.Println(value[n][bestT])
	var taken []int
	for t, s := bestT, n; t > 0; {
		it := items[take[s][t]]
		s = take[s][t]
		taken = append(taken, it.idx)
		t -= it.t
	}
	fmt.Println(len(taken))
	for i := len(taken) - 1; i >= 0; i-- {
		if i == 0 {
			fmt.Println(taken[i])
		} else {
			fmt.Print(taken[i], " ")
		}
	}
}


package main

import (
	"fmt"
	"sort"
)

type item struct {
	t, d, p, idx int
}

type byD []item

func (s byD) Len() int           { return len(s) }
func (s byD) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s byD) Less(i, j int) bool { return s[i].d < s[j].d }

const maxD = 2000

func main() {
	var n int
	fmt.Scan(&n)
	items := make([]item, n)
	for i := range items {
		fmt.Scan(&items[i].t, &items[i].d, &items[i].p)
		items[i].idx = i + 1
	}
	sort.Sort(byD(items))

	value := make([][]int, n+1)
	for i := range value {
		value[i] = make([]int, maxD+1)
		for j := range value[i] {
			value[i][j] = -1
		}
	}
	value[0][0] = 0
	take := make([][]int, n+1)
	for i := range take {
		take[i] = make([]int, maxD+1)
	}

	bestT := 0
	for i, it := range items {
		for t := maxD - 1; t >= 0; t-- {
			value[i+1][t] = value[i][t]
			take[i+1][t] = take[i][t]
		}
		for t := it.d - 1; t >= it.t; t-- {
			cur := value[i][t-it.t]
			if cur == -1 {
				continue
			}
			cur += it.p
			if value[i+1][t] < cur {
				value[i+1][t] = cur
				take[i+1][t] = i
				if value[i+1][bestT] < cur {
					bestT = t
				}
			}
		}
	}

	fmt.Println(value[n][bestT])
	var taken []int
	for t, s := bestT, n; t > 0; {
		it := items[take[s][t]]
		s = take[s][t]
		taken = append(taken, it.idx)
		t -= it.t
	}
	fmt.Println(len(taken))
	for i := len(taken) - 1; i >= 0; i-- {
		if i == 0 {
			fmt.Println(taken[i])
		} else {
			fmt.Print(taken[i], " ")
		}
	}
}


package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"sort"
)

type Item struct {
	Time, DestroyTime, Value, Index int
}
type Items []*Item

func (this Items) Len() int           { return len(this) }
func (this Items) Swap(i, j int)      { this[i], this[j] = this[j], this[i] }
func (this Items) Less(i, j int) bool { return this[i].DestroyTime < this[j].DestroyTime }

var dp [21][2001]int
var route [21][2001]int

func main() {
	bs, _ := ioutil.ReadAll(os.Stdin)
	reader := bytes.NewBuffer(bs)

	var n int

	fmt.Fscanf(reader, "%d\n", &n)
	var items Items
	items = make([]*Item, n)

	for i := 0; i < n; i++ {
		item := Item{}
		fmt.Fscanf(reader, "%d %d %d\n", &item.Time, &item.DestroyTime, &item.Value)
		item.Index = i + 1
		items[i] = &item
	}
	sort.Sort(items)

	for i := 1; i <= n; i++ {
		item := items[i-1]
		for j := 0; j <= 2000; j++ {
			if j != 0 {
				dp[i][j] = dp[i][j-1]
				route[i][j] = 1
			}
			if dp[i][j] < dp[i-1][j] {
				dp[i][j] = dp[i-1][j]
				route[i][j] = 2
			}
			if j < item.DestroyTime && j >= item.Time && dp[i][j] < dp[i-1][j-item.Time]+item.Value {
				dp[i][j] = dp[i-1][j-item.Time] + item.Value
				route[i][j] = 3
			}
		}
	}
	ans := make([]int, 0, n)
	itemPos, timePos := n, 2000
	for itemPos != 0 && timePos != 0 {
		if route[itemPos][timePos] == 3 {
			ans = append(ans, items[itemPos-1].Index)
			timePos = timePos - items[itemPos-1].Time
			itemPos--
		} else if route[itemPos][timePos] == 2 {
			itemPos--
		} else {
			timePos--
		}
	}
	fmt.Printf("%d\n%d\n", dp[n][2000], len(ans))

	for i := len(ans) - 1; i >= 0; i-- {
		fmt.Printf("%d ", ans[i])
	}
}


package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"sort"
)

type Item struct {
	Time, DestroyTime, Value, Index int
}
type Items []*Item

func (this Items) Len() int           { return len(this) }
func (this Items) Swap(i, j int)      { this[i], this[j] = this[j], this[i] }
func (this Items) Less(i, j int) bool { return this[i].DestroyTime < this[j].DestroyTime }

var dp [101][2001]int
var route [101][2001]int

func main() {
	bs, _ := ioutil.ReadAll(os.Stdin)
	reader := bytes.NewBuffer(bs)

	var n int

	fmt.Fscanf(reader, "%d\n", &n)
	var items Items
	items = make([]*Item, n)

	for i := 0; i < n; i++ {
		item := Item{}
		fmt.Fscanf(reader, "%d %d %d\n", &item.Time, &item.DestroyTime, &item.Value)
		item.Index = i + 1
		items[i] = &item
	}
	sort.Sort(items)

	for i := 1; i <= n; i++ {
		item := items[i-1]
		for j := 0; j <= 2000; j++ {
			if j != 0 {
				dp[i][j] = dp[i][j-1]
				route[i][j] = 1
			}
			if dp[i][j] < dp[i-1][j] {
				dp[i][j] = dp[i-1][j]
				route[i][j] = 2
			}
			if j < item.DestroyTime && j >= item.Time && dp[i][j] < dp[i-1][j-item.Time]+item.Value {
				dp[i][j] = dp[i-1][j-item.Time] + item.Value
				route[i][j] = 3
			}
		}
	}
	ans := make([]int, 0, n)
	itemPos, timePos := n, 2000
	for itemPos != 0 && timePos != 0 {
		if route[itemPos][timePos] == 3 {
			ans = append(ans, items[itemPos-1].Index)
			timePos = timePos - items[itemPos-1].Time
			itemPos--
		} else if route[itemPos][timePos] == 2 {
			itemPos--
		} else {
			timePos--
		}
	}
	fmt.Printf("%d\n%d\n", dp[n][2000], len(ans))

	for i := len(ans) - 1; i >= 0; i-- {
		fmt.Printf("%d ", ans[i])
	}
}


package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
	"sort"
)

// github.com/EndlessCheng/codeforces-go
func CF864E(_r io.Reader, out io.Writer) {
	in := bufio.NewReader(_r)
	type pair struct{ w, mxW, v, i int }

	var n int
	Fscan(in, &n)
	a := make([]pair, n)
	for i := range a {
		Fscan(in, &a[i].w, &a[i].mxW, &a[i].v)
		a[i].i = i + 1
	}
	sort.Slice(a, func(i, j int) bool { return a[i].mxW < a[j].mxW })

	m := a[n-1].mxW
	dp := make([]int, m)
	fa := make([][]int, n)
	for i := range fa {
		fa[i] = make([]int, m)
		for j := range fa[i] {
			fa[i][j] = -1
		}
	}
	for i, p := range a {
		w := p.w
		for j := p.mxW - 1; j >= w; j-- {
			if d := dp[j-w] + p.v; d > dp[j] {
				dp[j] = d
				fa[i][j] = j - w
			}
		}
	}
	mxJ := 0
	for j, v := range dp {
		if v > dp[mxJ] {
			mxJ = j
		}
	}
	Fprintln(out, dp[mxJ])
	ans := []int{}
	for i, j := n-1, mxJ; i >= 0; i-- {
		if fa[i][j] != -1 {
			ans = append(ans, a[i].i)
			j = fa[i][j]
		}
	}
	Fprintln(out, len(ans))
	for i := len(ans) - 1; i >= 0; i-- {
		Fprint(out, ans[i], " ")
	}
}

func main() { CF864E(os.Stdin, os.Stdout) }


package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
	"sort"
)

// github.com/EndlessCheng/codeforces-go
func CF864E(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()
	type pair struct{ w, mxW, v, i int }

	var n int
	Fscan(in, &n)
	a := make([]pair, n)
	for i := range a {
		Fscan(in, &a[i].w, &a[i].mxW, &a[i].v)
		a[i].i = i + 1
	}
	sort.Slice(a, func(i, j int) bool { return a[i].mxW < a[j].mxW })

	m := a[n-1].mxW
	dp := make([]int, m)
	fa := make([][]int, n)
	for i := range fa {
		fa[i] = make([]int, m)
		for j := range fa[i] {
			fa[i][j] = -1
		}
	}
	for i, p := range a {
		w := p.w
		for j := p.mxW - 1; j >= w; j-- {
			if d := dp[j-w] + p.v; d > dp[j] {
				dp[j] = d
				fa[i][j] = j - w
			}
		}
	}
	Fprintln(out, dp[m-1])
	ans := []int{}
	for i, j := n-1, m-1; i >= 0; i-- {
		if fa[i][j] != -1 {
			ans = append(ans, a[i].i)
			j = fa[i][j]
		}
	}
	Fprintln(out, len(ans))
	for i := len(ans) - 1; i >= 0; i-- {
		Fprint(out, ans[i], " ")
	}
}

func main() { CF864E(os.Stdin, os.Stdout) }


package main

import (
	"fmt"
	"bufio"
	"os"
	"strconv"
	"bytes"
	"sort"
)

type Node struct {
	num, p, d, t int
}

type Nodes []Node

func (nodes Nodes) Len() int {
	return len(nodes)
}

func (nodes Nodes) Less(i, j int) bool {
	return nodes[i].d < nodes[j].d
}

func (nodes Nodes) Swap(i, j int) {
	nodes[i], nodes[j] = nodes[j], nodes[i]
}

func solve() {
	n := readInt()
	a := make([]Node, n)
	for i := 0; i < n; i++ {
		a[i].t, a[i].d, a[i].p = readInt(), readInt(), readInt()
		a[i].num = i + 1
	}
	sort.Sort(Nodes(a))
	dp := make([][]int, n + 1)
	MAXD := 2001
	dp[0] = make([]int, MAXD)
	for i := 1; i <= n; i++ {
		dp[i] = make([]int, MAXD)
		for j := MAXD - 1; j >= 0; j-- {
			dp[i][j] = dp[i-1][j]
			if j < a[i-1].d && j - a[i-1].t >= 0 {
				dp[i][j] = max(dp[i-1][j-a[i-1].t] + a[i-1].p, dp[i][j])
			}
		}
	}
	pos := 0
	for i := 1; i < MAXD-1; i++ {
		if dp[n][i] > dp[n][pos] {
			pos = i
		}
	}
	ansValue := dp[n][pos]
	ansArray := make([]int, 0)
	for curRow := n; curRow > 0; curRow-- {
		if pos < a[curRow-1].d && pos - a[curRow-1].t >= 0 && dp[curRow][pos] == dp[curRow-1][pos-a[curRow-1].t] + a[curRow-1].p {
			pos -= a[curRow-1].t
			ansArray = append(ansArray, a[curRow-1].num)
		}
	}
	//sort.Reverse(sort.IntSlice(ansArray))

	var buf bytes.Buffer
	buf.WriteString(strconv.Itoa(ansValue))
	buf.WriteString("\n")
	buf.WriteString(strconv.Itoa(len(ansArray)))
	buf.WriteString("\n")
	if len(ansArray) > 0 {
		for i := range ansArray {
			buf.WriteString(strconv.Itoa(ansArray[len(ansArray)-i-1]))
			buf.WriteString(" ")
		}
	}
	fmt.Println(buf.String())
}

var scanner *bufio.Scanner

func main() {
	scanner = bufio.NewScanner(os.Stdin)
	const MaxTokenLength = 1024 * 1024
	scanner.Buffer(make([]byte, 0, MaxTokenLength), MaxTokenLength)
	scanner.Split(bufio.ScanWords)
	solve()
}

// IO

func readString() string {
	scanner.Scan()
	return scanner.Text()
}

func readInt() int {
	val, _ := strconv.Atoi(readString())
	return val
}

func readInt64() int64 {
	v, _ := strconv.ParseInt(readString(), 10, 64)
	return v
}

func readIntArray(sz int) []int {
	a := make([]int, sz)
	for i := 0; i < sz; i++ {
		a[i] = readInt()
	}
	return a
}

func readInt64Array(n int) []int64 {
	res := make([]int64, n)
	for i := 0; i < n; i++ {
		res[i] = readInt64()
	}
	return res
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}


package main

import (
	"fmt"
	"bufio"
	"os"
	"strconv"
	"bytes"
	"sort"
)

type Node struct {
	num, p, d, t int
}

type Nodes []Node

func (nodes Nodes) Len() int {
	return len(nodes)
}

func (nodes Nodes) Less(i, j int) bool {
	return nodes[i].d < nodes[j].d
}

func (nodes Nodes) Swap(i, j int) {
	nodes[i], nodes[j] = nodes[j], nodes[i]
}

func solve() {
	n := readInt()
	a := make([]Node, n)
	for i := 0; i < n; i++ {
		a[i].t, a[i].d, a[i].p = readInt(), readInt(), readInt()
		a[i].num = i + 1
	}
	sort.Sort(Nodes(a))
	dp := make([][]int, n + 1)
	MAXD := 2001
	dp[0] = make([]int, MAXD)
	for i := 1; i <= n; i++ {
		dp[i] = make([]int, MAXD)
		for j := MAXD - 1; j >= 0; j-- {
			dp[i][j] = dp[i-1][j]
			if j < a[i-1].d && j - a[i-1].t >= 0 {
				dp[i][j] = max(dp[i-1][j-a[i-1].t] + a[i-1].p, dp[i][j])
			}
		}
	}
	pos := 0
	for i := 1; i < MAXD-1; i++ {
		if dp[n][i] > dp[n][pos] {
			pos = i
		}
	}
	ansValue := dp[n][pos]
	ansArray := make([]int, 0)
	for curRow := n; curRow > 0; curRow-- {
		if pos < a[curRow-1].d && pos - a[curRow-1].t >= 0 && dp[curRow][pos] == dp[curRow-1][pos-a[curRow-1].t] + a[curRow-1].p {
			pos -= a[curRow-1].t
			ansArray = append(ansArray, a[curRow-1].num)
		}
	}
	sort.Reverse(sort.IntSlice(ansArray))

	fmt.Println(n)
	var buf bytes.Buffer
	buf.WriteString(strconv.Itoa(ansValue))
	buf.WriteString("\n")
	buf.WriteString(strconv.Itoa(len(ansArray)))
	buf.WriteString("\n")
	if len(ansArray) > 0 {
		for i := range ansArray {
			buf.WriteString(strconv.Itoa(ansArray[len(ansArray)-i-1]))
			buf.WriteString(" ")
		}
	}
	fmt.Println(buf.String())
}

var scanner *bufio.Scanner

func main() {
	scanner = bufio.NewScanner(os.Stdin)
	const MaxTokenLength = 1024 * 1024
	scanner.Buffer(make([]byte, 0, MaxTokenLength), MaxTokenLength)
	scanner.Split(bufio.ScanWords)
	solve()
}

// IO

func readString() string {
	scanner.Scan()
	return scanner.Text()
}

func readInt() int {
	val, _ := strconv.Atoi(readString())
	return val
}

func readInt64() int64 {
	v, _ := strconv.ParseInt(readString(), 10, 64)
	return v
}

func readIntArray(sz int) []int {
	a := make([]int, sz)
	for i := 0; i < sz; i++ {
		a[i] = readInt()
	}
	return a
}

func readInt64Array(n int) []int64 {
	res := make([]int64, n)
	for i := 0; i < n; i++ {
		res[i] = readInt64()
	}
	return res
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}


n = int(raw_input())
dp = [[0 for x in range(2001)] for x in range(n+1)]
track = [[[-1,-1] for x in range(2001)] for x in range(n+1)]
inds = [[-1 for x in range(2001)] for x in range(n+1)]
arr = []
for i in range(n):
  a,b,c = map(int,raw_input().split())
  arr.append([b,a,c,i])
arr = sorted(arr)
ans = 0
for i in range(1,n+1):
  b,a,c,ind = arr[i-1]
  for j in range(b-a-1,-1,-1):
    if dp[i-1][j]+c > dp[i][j+a]:
      dp[i][j+a] = dp[i-1][j]+c
      track[i][j+a] = [i-1,j]
      inds[i][j+a] = ind
      ans = max(ans,dp[i][j+a])
  for j in range(2001):
    if dp[i-1][j] > dp[i][j]:
      dp[i][j] = dp[i-1][j]
      track[i][j] = track[i-1][j]
      inds[i][j] = inds[i-1][j]
for i in range(2001):
  if dp[n][i]==ans:
    s = [n,i]
    break
arr = []
while track[s[0]][s[1]][1] != -1:
  arr.insert(0,inds[s[0]][s[1]]+1)
  s = track[s[0]][s[1]]
print ans
print len(arr)
print " ".join([str(x) for x in arr])
'''
5
1 2 4
1 2 5
1 5 6
1 4 6
1 3 6
'''


n = int(raw_input())
dp = [0 for x in range(2001)]
track = [-1 for x in range(2001)]
inds = [-1 for x in range(2001)]
for i in range(n):
  a,b,c = map(int,raw_input().split())
  for j in range(b-a-1,-1,-1):
    if dp[j]+c > dp[j+a]:
      dp[j+a] = dp[j]+c
      track[j+a] = j
      inds[j+a] = i
for i in range(2001):
  if dp[i]==max(dp):
    s = i
    break
arr = []
while track[s] != -1:
  arr.insert(0,inds[s]+1)
  s = track[s]
print max(dp)
print len(arr)
print " ".join([str(x) for x in arr])


n = int(raw_input())
dp = [0 for x in range(2001)]
track = [-1 for x in range(2001)]
inds = [-1 for x in range(2001)]
arr = []
for i in range(n):
  a,b,c = map(int,raw_input().split())
  arr.append([b,a,c,i])
arr = sorted(arr)
for i in range(n):
  b,a,c,ind = arr[i]
  for j in range(b-a-1,-1,-1):
    if dp[j]+c > dp[j+a]:
      dp[j+a] = dp[j]+c
      track[j+a] = j
      inds[j+a] = ind
for i in range(2001):
  if dp[i]==max(dp):
    s = i
    break
arr = []
while track[s] != -1:
  arr.insert(0,inds[s]+1)
  s = track[s]
print max(dp)
print len(arr)
print " ".join([str(x) for x in arr])


n = input()
items = []

for i in range(1, n + 1):
    items.append(map(int, raw_input().split()) + [i])

items.sort(key = lambda (i, j, k, l): j)

dp = [0]*2005
ans = [[] for i in range(2005)]

for i in range(1, n + 1):
    t, d, p, ind = items[i - 1]
    for j in range(d - 1, t - 1, -1):
        if dp[j] < dp[j - t] + p:
            dp[j] = dp[j - t] + p
            ans[j] = ans[j - t] + [ind]

m = max(dp)
b = ans[dp.index(m)]
print m
print len(b)
print " ".join(map(str, b))


n = input()
items = []

for i in range(1, n + 1):
    items.append(map(int, raw_input().split()) + [i])

items.sort(key = lambda (i, j, k, l): j)
memo = {}
def helper(i, time):
    if i == len(items):
        return 0, []
    label = i, time
    if label in memo:
        return memo[label]
    t, d, p, ind = items[i]
    if time + t < d:
        a, b = helper(i + 1, time + t)
        a += p
        b.append(ind)
        val = max(helper(i + 1, time), (a, b))
        memo[label] = val
        return val
    val = helper(i + 1, time)
    memo[label] = val
    return val

a, b = helper(0, 0)
print a
print len(b)
print " ".join(map(str, b[::-1]))


n = input()
items = []

for i in range(1, n + 1):
    items.append(map(int, raw_input().split()) + [i])

items.sort(key = lambda (i, j, k, l): j)
memo = {}

def helper(i, time):
    if i == len(items):
        return 0, set()
    label = i, time
    if label in memo:
        return memo[label]
    t, d, p, ind = items[i]
    if time + t < d:
        a, b = helper(i + 1, time + t)
        a += p
        b |= {ind}
        val = max(helper(i + 1, time), (a, b))
        memo[label] = val
        return val
    val = helper(i + 1, time)
    memo[label] = val
    return val

a, b = helper(0, 0)
print a
print len(b)
b = sorted(b, key = lambda i: min(k for k, j in enumerate(items) if j[-1] == i))
print " ".join(str(z) for z in b)


n = int(raw_input())
input = [(map(int, raw_input().split(" ")) + [str(i + 1)]) for i in xrange(n)]
P = [0 for _ in xrange(2001)]
S = [[] for _ in xrange(2001)]
input.sort(key=lambda x: x[1])
for t, d, p, i in input:
    for x in range(t, d)[::-1]:
        if P[x] < P[x - t] + p:
            P[x] = P[x - t] + p
            S[x] = S[x - t] + [i]
maxi = P.index(max(P))
print P[maxi]
print len(S[maxi])
print " ".join(S[maxi])


import copy
n = int(input())
arr = []
m = 0
for er in range(n):
    temp = list(map(int,input().split(" ")))
    temp.append(er+1)
    if(temp[0]<temp[1]):
        arr.append(temp)
        if(temp[1]>m):
            m = temp[1]
    else:
        n-=1
arr.sort(key = lambda x:x[1])
#print(arr)
temp=[]
for i in range(n):
    temp.append([0])
com = []
com.append(temp)
total = [0,0]
for i in range(1,m+1):
    temp = []
    for j in range(n+1):
        if(j==0):
            temp.append([0])
        else:
            p=arr[j-1]
            if(p[0]>i or p[1]<=i):
                temp.append(temp[j-1])
            else:
                te = i - p[0]
                ty = copy.deepcopy(com[te][j-1])
                ty[0]+=p[2]
                ty.append(j)
                if(total[0]<ty[0]):
                    total = ty
                if(temp[j-1][0]<ty[0]):
                    temp.append(ty)
                else:
                    temp.append(temp[j-1])
    #print(temp , " temp")
    com.append(temp)
#print(com)
print(total[0])
if(total[0]>0):
    print(len(total)-1)
    for i in range(1,len(total)):
        print(arr[total[i]-1][3] , end = " ")
else:
    print("0")


import copy

n = int(input())
arr = []
m = 0
for er in range(n):
    temp = list(map(int,input().split(" ")))
    temp.append(er+1)
    if(temp[0]<temp[1]):
        arr.append(temp)
        if(temp[1]>m):
            m = temp[1]
    else:
        n-=1
arr.sort(key = lambda x:x[1])

#print(arr)
temp=[]
for i in range(n):
    temp.append([0])
com = []
#print(temp)
com.append(temp)
total = [0,0]
for i in range(1,m+1):
    temp = []
    for j in range(n+1):
        if(j==0):
            temp.append([0])
        else:
            #print(j)
            p=arr[j-1]
            if(p[0]>i or p[1]<=i):
                temp.append(temp[j-1])
            else:
                te = i - p[0]
                ty = copy.deepcopy(com[te][j-1])
                #print(ty)
                ty[0]+=p[2]
                ty.append(j)
                if(total[0]<ty[0]):
                    total = ty
                if(temp[j-1][0]<ty[0]):
                    temp.append(ty)
                else:
                    temp.append(temp[j-1])
    #print(temp , " temp")
    com.append(temp)
#print(com)

print(total[0])
print(len(total)-1)
for i in range(1,len(total)):
    print(arr[total[i]-1][3] , end = " ")

''' print(" ")
            if(p[0]!=p[1]):
                k = i-p[0]
                ans = 0
                lis = [ans]
                print("i",i,"j",j , "k",k,"p[1]",p[1] )
                if(k<1):
                    lis=[0]
                elif(p[1]<i):
                    for qw in range(n):
                        if( ans < com[i-1][qw][0]):
                            lis = []
                            for rt in range(len(com[i-1][qw])):
                                lis.append(com[i-1][qw][rt])
                            ans = com[i-1][qw][0]
                else:
                    if(k==1):
                        ans = p[2]
                        lis[0] = ans
                        lis.append(p[3])
                    else:
                        for qw in range(n):
                            if( ans < com[k][qw][0]):
                                flag = 0
                                li = com[k][qw]
                                for op in range(1,len(li)):
                                    print(op,"li",li[op])
                                    if(li[op]==j):
                                        flag=1
                                        break
                                if(flag==0):
                                    ans = com[k][qw][0]
                                    lis = copy.deepcopy(li)
                        ans +=p[2]
                        lis[0] = ans
                        lis.append(p[3])
                temp.append(lis)
                print(lis)
            else:
                temp.append([0])'''


import copy

n = int(input())
arr = []
m = 0
for er in range(n):
    temp = list(map(int,input().split(" ")))
    temp.append(er+1)
    arr.append(temp)
    if(temp[1]>m):
        m = temp[1]
arr.sort(key = lambda x:x[1])

#print(arr)
temp=[]
for i in range(n):
    temp.append([0])
com = []
#print(temp)
com.append(temp)
total = [0,0]
for i in range(1,m+1):
    temp = []
    for j in range(n+1):
        if(j==0):
            temp.append([0])
        else:
            p=arr[j-1]
            if(p[0]>i or p[1]<i):
                temp.append(temp[j-1])
            else:
                te = i - p[0]
                ty = copy.deepcopy(com[te][j-1])
                #print(ty)
                ty[0]+=p[2]
                ty.append(j)
                if(total[0]<ty[0]):
                    total = ty
                if(temp[j-1][0]<ty[0]):
                    temp.append(ty)
                else:
                    temp.append(temp[j-1])
    #print(temp , " temp")
    com.append(temp)
#print(com)

print(total[0])
print(len(total)-1)
for i in range(1,len(total)):
    print(arr[total[i]-1][3] , end = " ")

''' print(" ")
            if(p[0]!=p[1]):
                k = i-p[0]
                ans = 0
                lis = [ans]
                print("i",i,"j",j , "k",k,"p[1]",p[1] )
                if(k<1):
                    lis=[0]
                elif(p[1]<i):
                    for qw in range(n):
                        if( ans < com[i-1][qw][0]):
                            lis = []
                            for rt in range(len(com[i-1][qw])):
                                lis.append(com[i-1][qw][rt])
                            ans = com[i-1][qw][0]
                else:
                    if(k==1):
                        ans = p[2]
                        lis[0] = ans
                        lis.append(p[3])
                    else:
                        for qw in range(n):
                            if( ans < com[k][qw][0]):
                                flag = 0
                                li = com[k][qw]
                                for op in range(1,len(li)):
                                    print(op,"li",li[op])
                                    if(li[op]==j):
                                        flag=1
                                        break
                                if(flag==0):
                                    ans = com[k][qw][0]
                                    lis = copy.deepcopy(li)
                        ans +=p[2]
                        lis[0] = ans
                        lis.append(p[3])
                temp.append(lis)
                print(lis)
            else:
                temp.append([0])'''


import copy
n = int(input())
arr = []
m = 0
for er in range(n):
    temp = list(map(int,input().split(" ")))
    temp.append(er+1)
    if(temp[0]<temp[1]):
        arr.append(temp)
        if(temp[1]>m):
            m = temp[1]
    else:
        n-=1
arr.sort(key = lambda x:x[1])
#print(arr)
temp=[]
for i in range(n):
    temp.append([0])
com = []
com.append(temp)
total = [0,0]
for i in range(1,m+1):
    temp = []
    for j in range(n+1):
        if(j==0):
            temp.append([0])
        else:
            p=arr[j-1]
            if(p[0]>i or p[1]<=i):
                temp.append(temp[j-1])
            else:
                te = i - p[0]
                ty = copy.deepcopy(com[te][j-1])
                ty[0]+=p[2]
                ty.append(j)
                if(total[0]<ty[0]):
                    total = ty
                if(temp[j-1][0]<ty[0]):
                    temp.append(ty)
                else:
                    temp.append(temp[j-1])
    #print(temp , " temp")
    com.append(temp)
#print(com)
print(total[0])
if(total[0]>0):
    print(len(total)-1)
    for i in range(1,len(total)):
        print(arr[total[i]-1][3] , end = " ")


import copy

n = int(input())
arr = []
m = 0
for er in range(n):
    temp = list(map(int,input().split(" ")))
    temp.append(er+1)
    if(temp[0]<temp[1]):
        arr.append(temp)
        if(temp[1]>m):
            m = temp[1]
    else:
        n-=1
arr.sort(key = lambda x:x[1])

#print(arr)
temp=[]
for i in range(n):
    temp.append([0])
com = []
#print(temp)
com.append(temp)
total = [0,0]
for i in range(1,m+1):
    temp = []
    for j in range(n+1):
        if(j==0):
            temp.append([0])
        else:
            #print(j)
            p=arr[j-1]
            if(p[0]>i or p[1]<i):
                temp.append(temp[j-1])
            else:
                te = i - p[0]
                ty = copy.deepcopy(com[te][j-1])
                #print(ty)
                ty[0]+=p[2]
                ty.append(j)
                if(total[0]<ty[0]):
                    total = ty
                if(temp[j-1][0]<ty[0]):
                    temp.append(ty)
                else:
                    temp.append(temp[j-1])
    #print(temp , " temp")
    com.append(temp)
#print(com)

print(total[0])
print(len(total)-1)
for i in range(1,len(total)):
    print(arr[total[i]-1][3] , end = " ")

''' print(" ")
            if(p[0]!=p[1]):
                k = i-p[0]
                ans = 0
                lis = [ans]
                print("i",i,"j",j , "k",k,"p[1]",p[1] )
                if(k<1):
                    lis=[0]
                elif(p[1]<i):
                    for qw in range(n):
                        if( ans < com[i-1][qw][0]):
                            lis = []
                            for rt in range(len(com[i-1][qw])):
                                lis.append(com[i-1][qw][rt])
                            ans = com[i-1][qw][0]
                else:
                    if(k==1):
                        ans = p[2]
                        lis[0] = ans
                        lis.append(p[3])
                    else:
                        for qw in range(n):
                            if( ans < com[k][qw][0]):
                                flag = 0
                                li = com[k][qw]
                                for op in range(1,len(li)):
                                    print(op,"li",li[op])
                                    if(li[op]==j):
                                        flag=1
                                        break
                                if(flag==0):
                                    ans = com[k][qw][0]
                                    lis = copy.deepcopy(li)
                        ans +=p[2]
                        lis[0] = ans
                        lis.append(p[3])
                temp.append(lis)
                print(lis)
            else:
                temp.append([0])'''


import copy

n = int(input())
arr = []
m = 0
for er in range(n):
    temp = list(map(int,input().split(" ")))
    temp.append(er+1)
    arr.append(temp)
    if(temp[1]>m):
        m = temp[1]
arr.sort(key = lambda x:x[1])

##print(arr)
temp=[]
for i in range(n):
    temp.append([0])
com = []
#print(temp)
com.append(temp)
for i in range(1,m+1):
    temp = []
    for j in range(n+1):
        if(j==0):
            temp.append([0])
        else:
            p=arr[j-1]
            if(p[0]>i or p[1]<i):
                temp.append(temp[j-1])
            else:
                te = i - p[0]
                ty = copy.deepcopy(com[te][j-1])
                #print(ty)
                ty[0]+=p[2]
                ty.append(j)
                if(temp[j-1][0]<ty[0]):
                    temp.append(ty)
                else:
                    temp.append(temp[j-1])
    #print(temp , " temp")
    com.append(temp)
#print(com)
ans = 0
li = []

total = com[m][n]

print(total[0])
print(len(total)-1)
for i in range(1,len(total)):
    print(arr[total[i]-1][3] , end = " ")

''' print(" ")
            if(p[0]!=p[1]):
                k = i-p[0]
                ans = 0
                lis = [ans]
                print("i",i,"j",j , "k",k,"p[1]",p[1] )
                if(k<1):
                    lis=[0]
                elif(p[1]<i):
                    for qw in range(n):
                        if( ans < com[i-1][qw][0]):
                            lis = []
                            for rt in range(len(com[i-1][qw])):
                                lis.append(com[i-1][qw][rt])
                            ans = com[i-1][qw][0]
                else:
                    if(k==1):
                        ans = p[2]
                        lis[0] = ans
                        lis.append(p[3])
                    else:
                        for qw in range(n):
                            if( ans < com[k][qw][0]):
                                flag = 0
                                li = com[k][qw]
                                for op in range(1,len(li)):
                                    print(op,"li",li[op])
                                    if(li[op]==j):
                                        flag=1
                                        break
                                if(flag==0):
                                    ans = com[k][qw][0]
                                    lis = copy.deepcopy(li)
                        ans +=p[2]
                        lis[0] = ans
                        lis.append(p[3])
                temp.append(lis)
                print(lis)
            else:
                temp.append([0])'''


from sys import stdin, stdout

T = 2001
INF = int(1e9)
n = int(stdin.readline())

items = []
for i in range(n):
    c, d, t = map(int, stdin.readline().split())
    items.append((d, c, t, i+1))

items.sort()
dp = [[None for i in range(T)] for j in range(n)]

def solve(pos, time):
    if pos >= n or time >= T:
        return 0
    if dp[pos][time] is not None:
        return dp[pos][time]
    d, c, t, i = items[pos]
    ans = solve(pos+1, time)
    if time + c < d:
        ans = max(ans, solve(pos+1, time + c) + t)
    dp[pos][time] = ans
    return ans

ans = []
def recover(pos, time):
    global ans
    if pos >= n or time >= T:
        return
    d, c, t, i = items[pos]
    if solve(pos+1, time) == solve(pos, time):
        recover(pos+1, time)
    else:
        ans.append(i)
        recover(pos+1, time + c)

stdout.write(str(solve(0, 0)) + '\n')
recover(0, 0)
stdout.write(str(len(ans)) + '\n')
for i in ans:
    stdout.write(str(i) + ' ')
stdout.write('\n')


from sys import stdin, stdout

T = 2001
INF = int(1e9)
n = int(stdin.readline())

items = []
for i in range(n):
    c, d, t = map(int, stdin.readline().split())
    items.append((d, c, t, i+1))

items.sort()
for d, c, t, i in items:
    print(d, c, t, i)
dp = [[None for i in range(T)] for j in range(n)]

def solve(pos, time):
    if pos >= n or time >= T:
        return 0
    if dp[pos][time] is not None:
        return dp[pos][time]
    d, c, t, i = items[pos]
    ans = solve(pos+1, time)
    if time + c < d:
        ans = max(ans, solve(pos+1, time + c) + t)
    dp[pos][time] = ans
    return ans

ans = []
def recover(pos, time):
    global ans
    if pos >= n or time >= T:
        return
    d, c, t, i = items[pos]
    if solve(pos+1, time) == solve(pos, time):
        recover(pos+1, time)
    else:
        ans.append(i)
        recover(pos+1, time + c)

stdout.write(str(solve(0, 0)) + '\n')
recover(0, 0)
stdout.write(str(len(ans)) + '\n')
for i in ans:
    stdout.write(str(i) + ' ')
stdout.write('\n')


n = int(input())

items = []
max_time = 0

for _ in range(n):
    t,d,p = map(int,input().split())
    max_time = max(max_time, d)
    items.append((t,d,p))

dp = [[(0,[]) for _ in range(n+1)] for _ in range(max_time+1)]

for time in range(1, max_time+1):
    for it in range(1, n+1):

        if time < items[it-1][0] or time >= items[it-1][1]:
            dp[time][it] = max(dp[time][it-1], dp[time-1][it])
        else:

            pick = dp[time-items[it-1][0]][it-1][0] + items[it-1][2]
            if dp[time][it-1][0] > pick :
                dp[time][it] = dp[time][it-1]
            else:

                dp[time][it] = (dp[time-items[it-1][0]][it-1][0] + items[it-1][2], list(dp[time-items[it-1][0]][it-1][1]))
                dp[time][it][1].append(it)

#print(dp)

res = max(dp[max_time])

print(res[0])
print(len(res[1]))
print(*res[1])


n = int(input())

items = []
max_time = 0

for i in range(1,n+1):
    t,d,p = map(int,input().split())
    max_time = max(max_time, d)
    items.append((t,d,p,i))

items.sort(key=lambda x: x[1])

dp = [[(0,[]) for _ in range(n+1)] for _ in range(max_time+1)]

for time in range(1, max_time+1):
    for it in range(1, n+1):

        if time < items[it-1][0] or time >= items[it-1][1]:
            dp[time][it] = max(dp[time][it-1], dp[time-1][it])
        else:

            pick = dp[time-items[it-1][0]][it-1][0] + items[it-1][2]
            if dp[time][it-1][0] > pick :
                dp[time][it] = max(dp[time][it-1], dp[time-1][it])
            else:

                dp[time][it] = (dp[time-items[it-1][0]][it-1][0] + items[it-1][2], list(dp[time-items[it-1][0]][it-1][1]))
                dp[time][it][1].append(items[it-1][3])

#print(dp)

res = max(dp[max_time])

print(res[0])
print(len(res[1]))
print(*res[1])


n = int(input())
T = 10
t, d, p, idx = [], [], [], []
ans = []
arr = []
for i in range(n):
    a, b, c = map(int, input().split())
    arr.append([a, b, c, i])
arr.sort(key=lambda x: x[0])
for i in arr:
    t.append(i[0]); d.append(i[1]); p.append(i[2]); idx.append(i[3])
# dp = [[0, -1] for i in range(10)]
# for i in range(1, 10):
#     # dp[i] = dp[i - 1].copy()

#     for j in range(n):
#         if d[j] > i >= t[j] and dp[i][0] < p[j] + dp[i - t[j]][0]:
#             dp[i][0] = p[j] + dp[i - t[j]][0]
#             dp[i][1] = j
# print(max(dp)[0])
# i = dp.index(max(dp))
# ans = []
# while i > 0 and dp[i][1] != -1:
#     ans.append(dp[i][1] + 1)
#     i = dp[i][1]
# print(len(ans))
# print(*ans[::-1])
dp = [[0 for j in range(n)] for i in range(10)]
for time in range(1, T):
    for i in range(n):
        # dp[time][i] = max(dp[time - 1][i], dp[time][i - 1])
        dp[time][i] = dp[time][i - 1]
        if d[i] > time >= t[i]:
            if i:
                dp[time][i] = max(dp[time][i], p[i] + dp[time - t[i]][i - 1])
            else:
                dp[time][i] = p[i]
# print(dp)
b = [0, 0]
for i in range(T):
    for j in range(n):
        if b[0] < dp[i][j]:
            b = [dp[i][j], [i, j]]
print(b[0])
b = b[1]
while dp[b[0]][b[1]] and b[0] > -1:
    if b[1] and dp[b[0]][b[1]] != dp[b[0]][b[1] - 1]:
        ans.append(b[1])
        b[0] -= t[b[1]]
    elif b[1] == 0:
        if dp[b[0]][b[1]]:
            ans.append(b[1])
        break
    b[1] -= 1
print(len(ans))
for i in ans[::-1]:
    print(idx[i] + 1, end=' ')


n = int(input())
T = 2001
t, d, p, idx = [], [], [], []
ans = []
arr = []
for i in range(n):
    a, b, c = map(int, input().split())
    arr.append([a, b, c, i])
arr.sort(key=lambda x: x[1])
for i in arr:
    t.append(i[0]); d.append(i[1]); p.append(i[2]); idx.append(i[3])
# dp = [[0, -1] for i in range(10)]
# for i in range(1, 10):
#     # dp[i] = dp[i - 1].copy()

#     for j in range(n):
#         if d[j] > i >= t[j] and dp[i][0] < p[j] + dp[i - t[j]][0]:
#             dp[i][0] = p[j] + dp[i - t[j]][0]
#             dp[i][1] = j
# print(max(dp)[0])
# i = dp.index(max(dp))
# ans = []
# while i > 0 and dp[i][1] != -1:
#     ans.append(dp[i][1] + 1)
#     i = dp[i][1]
# print(len(ans))
# print(*ans[::-1])
dp = [[0 for j in range(n)] for i in range(T)]
for time in range(1, T):
    for i in range(n):
        #dp[time][i] = max(dp[time - 1][i], dp[time][i - 1])
        dp[time][i] = dp[time][i - 1]
        if d[i] > time >= t[i]:
            if i:
                dp[time][i] = max(dp[time][i], p[i] + dp[time - t[i]][i - 1])
            else:
                dp[time][i] = p[i]
# print(dp)
b = [0, 0]
for i in range(T):
    for j in range(n):
        if b[0] < dp[i][j]:
            b = [dp[i][j], [i, j]]
print(b[0])
b = b[1]
while dp[b[0]][b[1]] and b[0] > -1:
    if b[1] and dp[b[0]][b[1]] != dp[b[0]][b[1] - 1]:
        ans.append(b[1])
        b[0] -= t[b[1]]
    elif b[1] == 0:
        if dp[b[0]][b[1]]:
            ans.append(b[1])
        break
    b[1] -= 1
print(len(ans))
for i in ans[::-1]:
    print(idx[i] + 1, end=' ')


from sys import stdin
input = stdin.readline
n = int(input())
T = 2001
t, d, p, idx = [], [], [], []
ans = []
arr = []
for i in range(n):
    a, b, c = map(int, input().split())
    arr.append([a, b, c, i])
arr.sort(key=lambda x: x[1])
for i in arr:
    t.append(i[0]); d.append(i[1]); p.append(i[2]); idx.append(i[3])
dp = [[0 for j in range(n)] for i in range(T)]
for time in range(1, T):
    for i in range(n):
        #dp[time][i] = max(dp[time - 1][i], dp[time][i - 1])
        dp[time][i] = dp[time][i - 1]
        if d[i] > time >= t[i]:
            if i:
                dp[time][i] = max(dp[time][i], p[i] + dp[time - t[i]][i - 1])
            else:
                dp[time][i] = p[i]
b = [0, [0 ,0]]
for i in range(T):
    for j in range(n):
        if b[0] < dp[i][j]:
            b = [dp[i][j], [i, j]]
print(b[0])
b = b[1]
while dp[b[0]][b[1]] and b[0] > -1:
    if b[1] and dp[b[0]][b[1]] != dp[b[0]][b[1] - 1]:
        ans.append(b[1])
        b[0] -= t[b[1]]
    elif b[1] == 0:
        if dp[b[0]][b[1]]:
            ans.append(b[1])
        break
    b[1] -= 1
print(len(ans))
for i in ans[::-1]:
    print(idx[i] + 1, end=' ')


n = int(input())
t, d, p = [], [], []
for _ in range(n):
    a, b, c = map(int, input().split())
    t.append(a); d.append(b); p.append(c)
dp = [[0, -1] for i in range(10)]
for i in range(1, 10):
    # dp[i] = dp[i - 1].copy()
    for j in range(n):
        if d[j] > i >= t[j] and dp[i][0] < p[j] + dp[i - t[j]][0]:
            dp[i][0] = p[j] + dp[i - t[j]][0]
            dp[i][1] = j
print(max(dp)[0])
i = dp.index(max(dp))
ans = []
while i > 0 and dp[i][1] != -1:
    ans.append(dp[i][1] + 1)
    i = dp[i][1]
print(len(ans))
print(*ans[::-1])